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,841 @@
1
+ __author__ = "Yuri E. Corilo"
2
+ __date__ = "Nov 11, 2019"
3
+
4
+ import json
5
+ from datetime import datetime, timezone
6
+ from pathlib import Path
7
+ from threading import Thread
8
+
9
+ import h5py
10
+ import toml
11
+ import numpy as np
12
+ from numpy import nan as NaN, empty
13
+ from pandas import DataFrame
14
+
15
+ from corems.encapsulation.constant import Atoms, Labels #Labels is accessed in the eval() function
16
+ from corems.encapsulation.output import parameter_to_dict
17
+ from corems.mass_spectrum.factory.MassSpectrumClasses import MassSpecfromFreq
18
+
19
+
20
+ class HighResMassSpecExport(Thread):
21
+ """A class for exporting high-resolution mass spectra.
22
+
23
+ Parameters
24
+ ----------
25
+ out_file_path : str
26
+ The output file path.
27
+ mass_spectrum : MassSpectrum
28
+ The mass spectrum to export.
29
+ output_type : str, optional
30
+ The type of output file. Defaults to 'excel'. Can be 'excel', 'csv', 'pandas' or 'hdf5'.
31
+
32
+ Attributes
33
+ ----------
34
+ output_file : Path
35
+ The output file path.
36
+ output_type : str
37
+ The type of output file.
38
+ mass_spectrum : MassSpectrum
39
+ The mass spectrum to export.
40
+ atoms_order_list : list
41
+ The list of assigned atoms in the order specified by Atoms.atoms_order list.
42
+ columns_label : list
43
+ The column labels in order.
44
+
45
+ Methods
46
+ -------
47
+ * save().
48
+ Save the mass spectrum data to the output file.
49
+ * run().
50
+ Run the export process.
51
+ * get_pandas_df().
52
+ Returns the mass spectrum data as a pandas DataFrame.
53
+ * write_settings(output_path, mass_spectrum).
54
+ Writes the settings of the mass spectrum to a JSON file.
55
+ * to_pandas(write_metadata=True).
56
+ Exports the mass spectrum data to a pandas DataFrame and saves it as a pickle file.
57
+ * to_excel(write_metadata=True).
58
+ Exports the mass spectrum data to an Excel file.
59
+ * to_csv(write_metadata=True).
60
+ Exports the mass spectrum data to a CSV file.
61
+ * to_json().
62
+ Exports the mass spectrum data to a JSON string.
63
+ * to_hdf().
64
+ Exports the mass spectrum data to an HDF5 file.
65
+ * parameters_to_toml().
66
+ Converts the mass spectrum parameters to a TOML string.
67
+ * parameters_to_json().
68
+ Converts the mass spectrum parameters to a JSON string.
69
+ * get_mass_spec_attrs(mass_spectrum).
70
+ Returns the mass spectrum attributes as a dictionary.
71
+ * get_all_used_atoms_in_order(mass_spectrum).
72
+ Returns the list of assigned atoms in the order specified by Atoms.atoms_order list.
73
+ * list_dict_to_list(mass_spectrum, is_hdf5=False).
74
+ Returns the mass spectrum data as a list of dictionaries.
75
+ * get_list_dict_data(mass_spectrum, include_no_match=True, include_isotopologues=True, isotopologue_inline=True, no_match_inline=False, is_hdf5=False).
76
+ Returns the mass spectrum data as a list of dictionaries.
77
+
78
+ """
79
+
80
+ def __init__(self, out_file_path, mass_spectrum, output_type="excel"):
81
+ Thread.__init__(self)
82
+
83
+ self.output_file = Path(out_file_path)
84
+
85
+ # 'excel', 'csv' or 'pandas'
86
+ self.output_type = output_type
87
+
88
+ self.mass_spectrum = mass_spectrum
89
+
90
+ # collect all assigned atoms and order them accordingly to the Atoms.atoms_order list
91
+ self.atoms_order_list = self.get_all_used_atoms_in_order(self.mass_spectrum)
92
+
93
+ self._init_columns()
94
+
95
+ def _init_columns(self):
96
+ """Initialize the columns for the mass spectrum output."""
97
+ # column labels in order
98
+ self.columns_label = [
99
+ "Index",
100
+ "m/z",
101
+ "Calibrated m/z",
102
+ "Calculated m/z",
103
+ "Peak Height",
104
+ "Peak Area",
105
+ "Resolving Power",
106
+ "S/N",
107
+ "Ion Charge",
108
+ "m/z Error (ppm)",
109
+ "m/z Error Score",
110
+ "Isotopologue Similarity",
111
+ "Confidence Score",
112
+ "DBE",
113
+ "O/C",
114
+ "H/C",
115
+ "Heteroatom Class",
116
+ "Ion Type",
117
+ "Adduct",
118
+ "Is Isotopologue",
119
+ "Mono Isotopic Index",
120
+ "Molecular Formula",
121
+ ]
122
+
123
+ @property
124
+ def output_type(self):
125
+ """Returns the output type of the mass spectrum."""
126
+ return self._output_type
127
+
128
+ @output_type.setter
129
+ def output_type(self, output_type):
130
+ output_types = ["excel", "csv", "pandas", "hdf5"]
131
+ if output_type in output_types:
132
+ self._output_type = output_type
133
+ else:
134
+ raise TypeError(
135
+ 'Supported types are "excel", "csv" or "pandas", %s entered'
136
+ % output_type
137
+ )
138
+
139
+ def save(self):
140
+ """Save the mass spectrum data to the output file.
141
+
142
+ Raises
143
+ ------
144
+ ValueError
145
+ If the output type is not supported.
146
+ """
147
+
148
+ if self.output_type == "excel":
149
+ self.to_excel()
150
+ elif self.output_type == "csv":
151
+ self.to_csv()
152
+ elif self.output_type == "pandas":
153
+ self.to_pandas()
154
+ elif self.output_type == "hdf5":
155
+ self.to_hdf()
156
+ else:
157
+ raise ValueError(
158
+ "Unkown output type: %s; it can be 'excel', 'csv' or 'pandas'"
159
+ % self.output_type
160
+ )
161
+
162
+ def run(self):
163
+ """Run the export process.
164
+
165
+ This method is called when the thread starts.
166
+ It calls the save method to perform the export."""
167
+ self.save()
168
+
169
+ def get_pandas_df(self, additional_columns=None):
170
+ """Returns the mass spectrum data as a pandas DataFrame.
171
+
172
+ Parameters
173
+ ----------
174
+ additional_columns : list, optional
175
+ Additional columns to include in the DataFrame. Defaults to None.
176
+ Suitable additional columns are: 'Aromaticity Index', 'NOSC', 'Aromaticity Index (modified)'.
177
+
178
+ Returns
179
+ -------
180
+ DataFrame
181
+ The mass spectrum data as a pandas DataFrame.
182
+ """
183
+ if additional_columns is not None:
184
+ possible_additional_columns = [
185
+ "Aromaticity Index",
186
+ "NOSC",
187
+ "Aromaticity Index (modified)",
188
+ ]
189
+ if additional_columns:
190
+ for column in additional_columns:
191
+ if column not in possible_additional_columns:
192
+ raise ValueError("Invalid additional column: %s" % column)
193
+ columns = (
194
+ self.columns_label
195
+ + additional_columns
196
+ + self.get_all_used_atoms_in_order(self.mass_spectrum)
197
+ )
198
+ else:
199
+ columns = self.columns_label + self.get_all_used_atoms_in_order(
200
+ self.mass_spectrum
201
+ )
202
+ dict_data_list = self.get_list_dict_data(
203
+ self.mass_spectrum, additional_columns=additional_columns
204
+ )
205
+ df = DataFrame(dict_data_list, columns=columns)
206
+ df.name = self.output_file
207
+ return df
208
+
209
+ def write_settings(self, output_path, mass_spectrum):
210
+ """Writes the settings of the mass spectrum to a JSON file.
211
+
212
+ Parameters
213
+ ----------
214
+ output_path : str
215
+ The output file path.
216
+ mass_spectrum : MassSpectrum
217
+ The mass spectrum to export.
218
+ """
219
+
220
+ import json
221
+
222
+ dict_setting = parameter_to_dict.get_dict_data_ms(mass_spectrum)
223
+
224
+ dict_setting["MassSpecAttrs"] = self.get_mass_spec_attrs(mass_spectrum)
225
+ dict_setting["analyzer"] = mass_spectrum.analyzer
226
+ dict_setting["instrument_label"] = mass_spectrum.instrument_label
227
+ dict_setting["sample_name"] = mass_spectrum.sample_name
228
+
229
+ with open(
230
+ output_path.with_suffix(".json"),
231
+ "w",
232
+ encoding="utf8",
233
+ ) as outfile:
234
+ output = json.dumps(
235
+ dict_setting, sort_keys=True, indent=4, separators=(",", ": ")
236
+ )
237
+ outfile.write(output)
238
+
239
+ def to_pandas(self, write_metadata=True):
240
+ """Exports the mass spectrum data to a pandas DataFrame and saves it as a pickle file.
241
+
242
+ Parameters
243
+ ----------
244
+ write_metadata : bool, optional
245
+ Whether to write the metadata to a JSON file. Defaults to True.
246
+ """
247
+
248
+ columns = self.columns_label + self.get_all_used_atoms_in_order(
249
+ self.mass_spectrum
250
+ )
251
+
252
+ dict_data_list = self.get_list_dict_data(self.mass_spectrum)
253
+
254
+ df = DataFrame(dict_data_list, columns=columns)
255
+
256
+ df.to_pickle(self.output_file.with_suffix(".pkl"))
257
+
258
+ if write_metadata:
259
+ self.write_settings(self.output_file, self.mass_spectrum)
260
+
261
+ def to_excel(self, write_metadata=True):
262
+ """Exports the mass spectrum data to an Excel file.
263
+
264
+ Parameters
265
+ ----------
266
+ write_metadata : bool, optional
267
+ Whether to write the metadata to a JSON file. Defaults to True.
268
+ """
269
+
270
+ columns = self.columns_label + self.get_all_used_atoms_in_order(
271
+ self.mass_spectrum
272
+ )
273
+
274
+ dict_data_list = self.get_list_dict_data(self.mass_spectrum)
275
+
276
+ df = DataFrame(dict_data_list, columns=columns)
277
+
278
+ df.to_excel(self.output_file.with_suffix(".xlsx"))
279
+
280
+ if write_metadata:
281
+ self.write_settings(self.output_file, self.mass_spectrum)
282
+
283
+ def to_csv(self, write_metadata=True):
284
+ """Exports the mass spectrum data to a CSV file.
285
+
286
+ Parameters
287
+ ----------
288
+ write_metadata : bool, optional
289
+ Whether to write the metadata to a JSON file. Defaults to True.
290
+ """
291
+
292
+ columns = self.columns_label + self.get_all_used_atoms_in_order(
293
+ self.mass_spectrum
294
+ )
295
+
296
+ dict_data_list = self.get_list_dict_data(self.mass_spectrum)
297
+
298
+ import csv
299
+
300
+ try:
301
+ with open(self.output_file.with_suffix(".csv"), "w", newline="") as csvfile:
302
+ writer = csv.DictWriter(csvfile, fieldnames=columns)
303
+ writer.writeheader()
304
+ for data in dict_data_list:
305
+ writer.writerow(data)
306
+ if write_metadata:
307
+ self.write_settings(self.output_file, self.mass_spectrum)
308
+
309
+ except IOError as ioerror:
310
+ print(ioerror)
311
+
312
+ def to_json(self):
313
+ """Exports the mass spectrum data to a JSON string."""
314
+
315
+ columns = self.columns_label + self.get_all_used_atoms_in_order(
316
+ self.mass_spectrum
317
+ )
318
+
319
+ dict_data_list = self.get_list_dict_data(self.mass_spectrum)
320
+
321
+ df = DataFrame(dict_data_list, columns=columns)
322
+
323
+ # for key, values in dict_data.items():
324
+ # if not values: dict_data[key] = NaN
325
+
326
+ # output = json.dumps(dict_data, sort_keys=True, indent=4, separators=(',', ': '))
327
+ return df.to_json(orient="records")
328
+
329
+ def add_mass_spectrum_to_hdf5(
330
+ self,
331
+ hdf_handle,
332
+ mass_spectrum,
333
+ group_key,
334
+ mass_spectra_group=None,
335
+ export_raw=True,
336
+ ):
337
+ """Adds the mass spectrum data to an HDF5 file.
338
+
339
+ Parameters
340
+ ----------
341
+ hdf_handle : h5py.File
342
+ The HDF5 file handle.
343
+ mass_spectrum : MassSpectrum
344
+ The mass spectrum to add to the HDF5 file.
345
+ group_key : str
346
+ The group key (where to add the mass spectrum data within the HDF5 file).
347
+ mass_spectra_group : h5py.Group, optional
348
+ The mass spectra group. Defaults to None (no group, mass spectrum is added to the root).
349
+ export_raw : bool, optional
350
+ Whether to export the raw data. Defaults to True.
351
+ If False, only the processed data (peaks) is exported (essentially centroided data).
352
+ """
353
+ if mass_spectra_group is None:
354
+ # Check if the file has the necessary attributes and add them if not
355
+ # This assumes that if there is a mass_spectra_group, these attributes were already added to the file
356
+ if not hdf_handle.attrs.get("date_utc"):
357
+ timenow = str(
358
+ datetime.now(timezone.utc).strftime("%d/%m/%Y %H:%M:%S %Z")
359
+ )
360
+ hdf_handle.attrs["date_utc"] = timenow
361
+ hdf_handle.attrs["file_name"] = mass_spectrum.filename.name
362
+ hdf_handle.attrs["data_structure"] = "mass_spectrum"
363
+ hdf_handle.attrs["analyzer"] = mass_spectrum.analyzer
364
+ hdf_handle.attrs["instrument_label"] = mass_spectrum.instrument_label
365
+ hdf_handle.attrs["sample_name"] = mass_spectrum.sample_name
366
+
367
+ list_results = self.list_dict_to_list(mass_spectrum, is_hdf5=True)
368
+
369
+ dict_ms_attrs = self.get_mass_spec_attrs(mass_spectrum)
370
+
371
+ setting_dicts = parameter_to_dict.get_dict_data_ms(mass_spectrum)
372
+
373
+ columns_labels = json.dumps(
374
+ self.columns_label + self.get_all_used_atoms_in_order(mass_spectrum),
375
+ sort_keys=False,
376
+ indent=4,
377
+ separators=(",", ": "),
378
+ )
379
+
380
+ group_key = group_key
381
+
382
+ if mass_spectra_group is not None:
383
+ hdf_handle = mass_spectra_group
384
+
385
+ if group_key not in hdf_handle.keys():
386
+ scan_group = hdf_handle.create_group(group_key)
387
+
388
+ # If there is raw data (from profile data) save it
389
+ if not mass_spectrum.is_centroid and export_raw:
390
+ mz_abun_array = empty(shape=(2, len(mass_spectrum.abundance_profile)), dtype=np.float32)
391
+
392
+ mz_abun_array[0] = mass_spectrum.abundance_profile
393
+ mz_abun_array[1] = mass_spectrum.mz_exp_profile
394
+
395
+ raw_ms_dataset = scan_group.create_dataset(
396
+ "raw_ms", data=mz_abun_array, dtype="f4", compression="gzip", compression_opts=9, chunks=True, shuffle=True, fletcher32=True
397
+ )
398
+
399
+ # Add metadata to the raw_ms dataset when it exists
400
+ raw_ms_dataset.attrs["MassSpecAttrs"] = json.dumps(dict_ms_attrs)
401
+
402
+ if isinstance(mass_spectrum, MassSpecfromFreq):
403
+ raw_ms_dataset.attrs["TransientSetting"] = json.dumps(
404
+ setting_dicts.get("TransientSetting"),
405
+ sort_keys=False,
406
+ indent=4,
407
+ separators=(",", ": "),
408
+ )
409
+ else:
410
+ # For centroided data, store metadata directly on the scan group
411
+ scan_group.attrs["MassSpecAttrs"] = json.dumps(dict_ms_attrs)
412
+
413
+ if isinstance(mass_spectrum, MassSpecfromFreq):
414
+ scan_group.attrs["TransientSetting"] = json.dumps(
415
+ setting_dicts.get("TransientSetting"),
416
+ sort_keys=False,
417
+ indent=4,
418
+ separators=(",", ": "),
419
+ )
420
+
421
+ else:
422
+ scan_group = hdf_handle.get(group_key)
423
+
424
+ # if there is not processed data len = 0, otherwise len() will return next index
425
+ index_processed_data = str(len(scan_group.keys()))
426
+
427
+ timenow = str(datetime.now(timezone.utc).strftime("%d/%m/%Y %H:%M:%S %Z"))
428
+
429
+ # Convert list_results to numpy array and optimize data types
430
+ array_results = np.array(list_results)
431
+
432
+ # Apply data type optimization for numeric columns
433
+ if array_results.dtype == np.float64:
434
+ array_results = array_results.astype(np.float32)
435
+ elif array_results.dtype == np.int64:
436
+ array_results = array_results.astype(np.int32)
437
+
438
+ processed_dset = scan_group.create_dataset(
439
+ index_processed_data, data=array_results, compression="gzip", compression_opts=9, chunks=True, shuffle=True, fletcher32=True
440
+ )
441
+
442
+ processed_dset.attrs["date_utc"] = timenow
443
+
444
+ processed_dset.attrs["ColumnsLabels"] = columns_labels
445
+
446
+ processed_dset.attrs["MoleculaSearchSetting"] = json.dumps(
447
+ setting_dicts.get("MoleculaSearch"),
448
+ sort_keys=False,
449
+ indent=4,
450
+ separators=(",", ": "),
451
+ )
452
+
453
+ processed_dset.attrs["MassSpecPeakSetting"] = json.dumps(
454
+ setting_dicts.get("MassSpecPeak"),
455
+ sort_keys=False,
456
+ indent=4,
457
+ separators=(",", ": "),
458
+ )
459
+
460
+ processed_dset.attrs["MassSpectrumSetting"] = json.dumps(
461
+ setting_dicts.get("MassSpectrum"),
462
+ sort_keys=False,
463
+ indent=4,
464
+ separators=(",", ": "),
465
+ )
466
+
467
+ def to_hdf(self):
468
+ """Exports the mass spectrum data to an HDF5 file."""
469
+
470
+ with h5py.File(self.output_file.with_suffix(".hdf5"), "a") as hdf_handle:
471
+ self.add_mass_spectrum_to_hdf5(
472
+ hdf_handle, self.mass_spectrum, str(self.mass_spectrum.scan_number)
473
+ )
474
+
475
+ def parameters_to_toml(self):
476
+ """Converts the mass spectrum parameters to a TOML string.
477
+
478
+ Returns
479
+ -------
480
+ str
481
+ The TOML string of the mass spectrum parameters.
482
+ """
483
+
484
+ dict_setting = parameter_to_dict.get_dict_data_ms(self.mass_spectrum)
485
+
486
+ dict_setting["MassSpecAttrs"] = self.get_mass_spec_attrs(self.mass_spectrum)
487
+ dict_setting["analyzer"] = self.mass_spectrum.analyzer
488
+ dict_setting["instrument_label"] = self.mass_spectrum.instrument_label
489
+ dict_setting["sample_name"] = self.mass_spectrum.sample_name
490
+
491
+ output = toml.dumps(dict_setting)
492
+
493
+ return output
494
+
495
+ def parameters_to_json(self):
496
+ """Converts the mass spectrum parameters to a JSON string.
497
+
498
+ Returns
499
+ -------
500
+ str
501
+ The JSON string of the mass spectrum parameters.
502
+ """
503
+
504
+ dict_setting = parameter_to_dict.get_dict_data_ms(self.mass_spectrum)
505
+
506
+ dict_setting["MassSpecAttrs"] = self.get_mass_spec_attrs(self.mass_spectrum)
507
+ dict_setting["analyzer"] = self.mass_spectrum.analyzer
508
+ dict_setting["instrument_label"] = self.mass_spectrum.instrument_label
509
+ dict_setting["sample_name"] = self.mass_spectrum.sample_name
510
+
511
+ output = json.dumps(dict_setting)
512
+
513
+ return output
514
+
515
+ def get_mass_spec_attrs(self, mass_spectrum):
516
+ """Returns the mass spectrum attributes as a dictionary.
517
+
518
+ Parameters
519
+ ----------
520
+ mass_spectrum : MassSpectrum
521
+ The mass spectrum to export.
522
+
523
+ Returns
524
+ -------
525
+ dict
526
+ The mass spectrum attributes.
527
+ """
528
+
529
+ dict_ms_attrs = {}
530
+ dict_ms_attrs["polarity"] = mass_spectrum.polarity
531
+ dict_ms_attrs["rt"] = mass_spectrum.retention_time
532
+ dict_ms_attrs["tic"] = mass_spectrum.tic
533
+ dict_ms_attrs["mobility_scan"] = mass_spectrum.mobility_scan
534
+ dict_ms_attrs["mobility_rt"] = mass_spectrum.mobility_rt
535
+ dict_ms_attrs["Aterm"] = mass_spectrum.Aterm
536
+ dict_ms_attrs["Bterm"] = mass_spectrum.Bterm
537
+ dict_ms_attrs["Cterm"] = mass_spectrum.Cterm
538
+ dict_ms_attrs["baseline_noise"] = mass_spectrum.baseline_noise
539
+ dict_ms_attrs["baseline_noise_std"] = mass_spectrum.baseline_noise_std
540
+
541
+ return dict_ms_attrs
542
+
543
+ def get_all_used_atoms_in_order(self, mass_spectrum):
544
+ """Returns the list of assigned atoms in the order specified by Atoms.atoms_order list.
545
+
546
+ Parameters
547
+ ----------
548
+ mass_spectrum : MassSpectrum
549
+ The mass spectrum to export.
550
+
551
+ Returns
552
+ -------
553
+ list
554
+ The list of assigned atoms in the order specified by Atoms.atoms_order list.
555
+ """
556
+
557
+ atoms_in_order = Atoms.atoms_order
558
+ all_used_atoms = set()
559
+ if mass_spectrum:
560
+ for ms_peak in mass_spectrum:
561
+ if ms_peak:
562
+ for m_formula in ms_peak:
563
+ for atom in m_formula.atoms:
564
+ all_used_atoms.add(atom)
565
+
566
+ def sort_method(atom):
567
+ return [atoms_in_order.index(atom)]
568
+
569
+ return sorted(all_used_atoms, key=sort_method)
570
+
571
+ def list_dict_to_list(self, mass_spectrum, is_hdf5=False):
572
+ """Returns the mass spectrum data as a list of dictionaries.
573
+
574
+ Parameters
575
+ ----------
576
+ mass_spectrum : MassSpectrum
577
+ The mass spectrum to export.
578
+ is_hdf5 : bool, optional
579
+ Whether the mass spectrum is being exported to an HDF5 file. Defaults to False.
580
+
581
+ Returns
582
+ -------
583
+ list
584
+ The mass spectrum data as a list of dictionaries.
585
+ """
586
+
587
+ column_labels = self.columns_label + self.get_all_used_atoms_in_order(
588
+ mass_spectrum
589
+ )
590
+
591
+ dict_list = self.get_list_dict_data(mass_spectrum, is_hdf5=is_hdf5)
592
+
593
+ all_lines = []
594
+ for dict_res in dict_list:
595
+ result_line = [NaN] * len(column_labels)
596
+
597
+ for label, value in dict_res.items():
598
+ label_index = column_labels.index(label)
599
+ result_line[label_index] = value
600
+
601
+ all_lines.append(result_line)
602
+
603
+ return all_lines
604
+
605
+ def get_list_dict_data(
606
+ self,
607
+ mass_spectrum,
608
+ include_no_match=True,
609
+ include_isotopologues=True,
610
+ isotopologue_inline=True,
611
+ no_match_inline=False,
612
+ is_hdf5=False,
613
+ additional_columns=None,
614
+ ):
615
+ """Returns the mass spectrum data as a list of dictionaries.
616
+
617
+ Parameters
618
+ ----------
619
+ mass_spectrum : MassSpectrum
620
+ The mass spectrum to export.
621
+ include_no_match : bool, optional
622
+ Whether to include unassigned (no match) data. Defaults to True.
623
+ include_isotopologues : bool, optional
624
+ Whether to include isotopologues. Defaults to True.
625
+ isotopologue_inline : bool, optional
626
+ Whether to include isotopologues inline. Defaults to True.
627
+ no_match_inline : bool, optional
628
+ Whether to include unassigned (no match) data inline. Defaults to False.
629
+ is_hdf5 : bool, optional
630
+ Whether the mass spectrum is being exported to an HDF5 file. Defaults to False.
631
+
632
+ Returns
633
+ -------
634
+ list
635
+ The mass spectrum data as a list of dictionaries.
636
+ """
637
+
638
+ dict_data_list = []
639
+
640
+ if is_hdf5:
641
+ encode = ".encode('utf-8')"
642
+ else:
643
+ encode = ""
644
+
645
+ def add_no_match_dict_data(index, ms_peak):
646
+ """
647
+ Export dictionary of mspeak info for unassigned (no match) data
648
+ """
649
+ dict_result = {
650
+ "Index": index,
651
+ "m/z": ms_peak._mz_exp,
652
+ "Calibrated m/z": ms_peak.mz_exp,
653
+ "Peak Height": ms_peak.abundance,
654
+ "Peak Area": ms_peak.area,
655
+ "Resolving Power": ms_peak.resolving_power,
656
+ "S/N": ms_peak.signal_to_noise,
657
+ "Ion Charge": ms_peak.ion_charge,
658
+ "Heteroatom Class": eval("Labels.unassigned{}".format(encode)),
659
+ }
660
+
661
+ dict_data_list.append(dict_result)
662
+
663
+ def add_match_dict_data(index, ms_peak, mformula, additional_columns=None):
664
+ """
665
+ Export dictionary of mspeak info for assigned (match) data
666
+ """
667
+ formula_dict = mformula.to_dict()
668
+
669
+ dict_result = {
670
+ "Index": index,
671
+ "m/z": ms_peak._mz_exp,
672
+ "Calibrated m/z": ms_peak.mz_exp,
673
+ "Calculated m/z": mformula.mz_calc,
674
+ "Peak Height": ms_peak.abundance,
675
+ "Peak Area": ms_peak.area,
676
+ "Resolving Power": ms_peak.resolving_power,
677
+ "S/N": ms_peak.signal_to_noise,
678
+ "Ion Charge": ms_peak.ion_charge,
679
+ "m/z Error (ppm)": mformula.mz_error,
680
+ "Confidence Score": mformula.confidence_score,
681
+ "Isotopologue Similarity": mformula.isotopologue_similarity,
682
+ "m/z Error Score": mformula.average_mz_error_score,
683
+ "DBE": mformula.dbe,
684
+ "Heteroatom Class": eval("mformula.class_label{}".format(encode)),
685
+ "H/C": mformula.H_C,
686
+ "O/C": mformula.O_C,
687
+ "Ion Type": eval("mformula.ion_type.lower(){}".format(encode)),
688
+ "Is Isotopologue": int(mformula.is_isotopologue),
689
+ "Molecular Formula": eval("mformula.string{}".format(encode)),
690
+ }
691
+ if additional_columns is not None:
692
+ possible_dict = {
693
+ "Aromaticity Index": mformula.A_I,
694
+ "NOSC": mformula.nosc,
695
+ "Aromaticity Index (modified)": mformula.A_I_mod,
696
+ }
697
+ for column in additional_columns:
698
+ dict_result[column] = possible_dict.get(column)
699
+
700
+ if mformula.adduct_atom:
701
+ dict_result["Adduct"] = eval("mformula.adduct_atom{}".format(encode))
702
+
703
+ if mformula.is_isotopologue:
704
+ dict_result["Mono Isotopic Index"] = mformula.mspeak_index_mono_isotopic
705
+
706
+ if self.atoms_order_list is None:
707
+ atoms_order_list = self.get_all_used_atoms_in_order(mass_spectrum)
708
+ else:
709
+ atoms_order_list = self.atoms_order_list
710
+
711
+ for atom in atoms_order_list:
712
+ if atom in formula_dict.keys():
713
+ dict_result[atom] = formula_dict.get(atom)
714
+
715
+ dict_data_list.append(dict_result)
716
+
717
+ score_methods = mass_spectrum.molecular_search_settings.score_methods
718
+ selected_score_method = (
719
+ mass_spectrum.molecular_search_settings.output_score_method
720
+ )
721
+
722
+ if selected_score_method in score_methods:
723
+ # temp set score method as the one chosen in the output
724
+ current_method = mass_spectrum.molecular_search_settings.score_method
725
+ mass_spectrum.molecular_search_settings.score_method = selected_score_method
726
+
727
+ for index, ms_peak in enumerate(mass_spectrum):
728
+ # print(ms_peak.mz_exp)
729
+
730
+ if ms_peak:
731
+ m_formula = ms_peak.best_molecular_formula_candidate
732
+
733
+ if m_formula:
734
+ if not m_formula.is_isotopologue:
735
+ add_match_dict_data(
736
+ index,
737
+ ms_peak,
738
+ m_formula,
739
+ additional_columns=additional_columns,
740
+ )
741
+
742
+ for (
743
+ iso_mspeak_index,
744
+ iso_mf_formula,
745
+ ) in m_formula.mspeak_mf_isotopologues_indexes:
746
+ iso_ms_peak = mass_spectrum[iso_mspeak_index]
747
+ add_match_dict_data(
748
+ iso_mspeak_index,
749
+ iso_ms_peak,
750
+ iso_mf_formula,
751
+ additional_columns=additional_columns,
752
+ )
753
+ else:
754
+ if include_no_match and no_match_inline:
755
+ add_no_match_dict_data(index, ms_peak)
756
+
757
+ if include_no_match and not no_match_inline:
758
+ for index, ms_peak in enumerate(mass_spectrum):
759
+ if not ms_peak:
760
+ add_no_match_dict_data(index, ms_peak)
761
+ # reset score method as the one chosen in the output
762
+ mass_spectrum.molecular_search_settings.score_method = current_method
763
+
764
+ else:
765
+ for index, ms_peak in enumerate(mass_spectrum):
766
+ # check if there is a molecular formula candidate for the msPeak
767
+
768
+ if ms_peak:
769
+ # m_formula = ms_peak.molecular_formula_lowest_error
770
+ for m_formula in ms_peak:
771
+ if mass_spectrum.molecular_search_settings.output_min_score > 0:
772
+ if (
773
+ m_formula.confidence_score
774
+ >= mass_spectrum.molecular_search_settings.output_min_score
775
+ ):
776
+ if m_formula.is_isotopologue: # isotopologues inline
777
+ if include_isotopologues and isotopologue_inline:
778
+ add_match_dict_data(
779
+ index,
780
+ ms_peak,
781
+ m_formula,
782
+ additional_columns=additional_columns,
783
+ )
784
+ else:
785
+ add_match_dict_data(
786
+ index,
787
+ ms_peak,
788
+ m_formula,
789
+ additional_columns=additional_columns,
790
+ ) # add monoisotopic peak
791
+
792
+ # cutoff because of low score
793
+ else:
794
+ add_no_match_dict_data(index, ms_peak)
795
+
796
+ else:
797
+ if m_formula.is_isotopologue: # isotopologues inline
798
+ if include_isotopologues and isotopologue_inline:
799
+ add_match_dict_data(
800
+ index,
801
+ ms_peak,
802
+ m_formula,
803
+ additional_columns=additional_columns,
804
+ )
805
+ else:
806
+ add_match_dict_data(
807
+ index,
808
+ ms_peak,
809
+ m_formula,
810
+ additional_columns=additional_columns,
811
+ ) # add monoisotopic peak
812
+ else:
813
+ # include not_match
814
+ if include_no_match and no_match_inline:
815
+ add_no_match_dict_data(index, ms_peak)
816
+
817
+ if include_isotopologues and not isotopologue_inline:
818
+ for index, ms_peak in enumerate(mass_spectrum):
819
+ for m_formula in ms_peak:
820
+ if m_formula.is_isotopologue:
821
+ if (
822
+ m_formula.confidence_score
823
+ >= mass_spectrum.molecular_search_settings.output_min_score
824
+ ):
825
+ add_match_dict_data(
826
+ index,
827
+ ms_peak,
828
+ m_formula,
829
+ additional_columns=additional_columns,
830
+ )
831
+
832
+ if include_no_match and not no_match_inline:
833
+ for index, ms_peak in enumerate(mass_spectrum):
834
+ if not ms_peak:
835
+ add_no_match_dict_data(index, ms_peak)
836
+
837
+ # remove duplicated add_match data possibly introduced on the output_score_filter step
838
+ res = []
839
+ [res.append(x) for x in dict_data_list if x not in res]
840
+
841
+ return res