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
File without changes
File without changes
@@ -0,0 +1,531 @@
1
+ __author__ = "Yuri E. Corilo"
2
+ __date__ = "Nov 11, 2019"
3
+
4
+ from copy import deepcopy
5
+ from io import BytesIO
6
+ from pathlib import Path
7
+
8
+ import chardet
9
+ from bs4 import BeautifulSoup
10
+ from pandas import read_csv, read_excel, read_pickle
11
+ from pandas.core.frame import DataFrame
12
+ from s3path import S3Path
13
+
14
+ from corems.encapsulation.constant import Labels
15
+ from corems.encapsulation.factory.parameters import default_parameters
16
+ from corems.encapsulation.factory.processingSetting import DataInputSetting
17
+ from corems.encapsulation.input.parameter_from_json import (
18
+ load_and_set_parameters_class,
19
+ load_and_set_parameters_ms,
20
+ load_and_set_toml_parameters_class,
21
+ )
22
+
23
+
24
+ class MassListBaseClass:
25
+ """The MassListBaseClass object reads mass list data types and returns the mass spectrum obj
26
+
27
+ Parameters
28
+ ----------
29
+ file_location : Path or S3Path
30
+ Full data path.
31
+ isCentroid : bool, optional
32
+ Determines the mass spectrum data structure. If set to True, it assumes centroid mode. If set to False, it assumes profile mode and attempts to peak pick. Default is True.
33
+ analyzer : str, optional
34
+ The analyzer used for the mass spectrum. Default is 'Unknown'.
35
+ instrument_label : str, optional
36
+ The label of the instrument used for the mass spectrum. Default is 'Unknown'.
37
+ sample_name : str, optional
38
+ The name of the sample. Default is None.
39
+ header_lines : int, optional
40
+ The number of lines to skip in the file, including the column labels line. Default is 0.
41
+ isThermoProfile : bool, optional
42
+ Determines the number of expected columns in the file. If set to True, only m/z and intensity columns are expected. Signal-to-noise ratio (S/N) and resolving power (RP) will be calculated based on the data. Default is False.
43
+ headerless : bool, optional
44
+ If True, assumes that there are no headers present in the file (e.g., a .xy file from Bruker) and assumes two columns: m/z and intensity. Default is False.
45
+
46
+ Attributes
47
+ ----------
48
+ parameters : DataInputSetting
49
+ The data input settings for the mass spectrum.
50
+ data_type : str
51
+ The type of data in the file.
52
+ delimiter : str
53
+ The delimiter used to read text-based files.
54
+
55
+ Methods
56
+ -------
57
+ * set_parameter_from_toml(parameters_path). Sets the data input settings from a TOML file.
58
+ * set_parameter_from_json(parameters_path). Sets the data input settings from a JSON file.
59
+ * get_dataframe(). Reads the file and returns the data as a pandas DataFrame.
60
+ * load_settings(mass_spec_obj, output_parameters). Loads the settings for the mass spectrum.
61
+ * get_output_parameters(polarity, scan_index=0). Returns the output parameters for the mass spectrum.
62
+ * clean_data_frame(dataframe). Cleans the data frame by removing columns that are not in the expected columns set.
63
+
64
+ """
65
+
66
+ def __init__(
67
+ self,
68
+ file_location: Path | S3Path,
69
+ isCentroid: bool = True,
70
+ analyzer: str = "Unknown",
71
+ instrument_label: str = "Unknown",
72
+ sample_name: str = None,
73
+ header_lines: int = 0,
74
+ isThermoProfile: bool = False,
75
+ headerless: bool = False,
76
+ ):
77
+ self.file_location = (
78
+ Path(file_location) if isinstance(file_location, str) else file_location
79
+ )
80
+
81
+ if not self.file_location.exists():
82
+ raise FileExistsError("File does not exist: %s" % file_location)
83
+
84
+ # (newline="\n")
85
+
86
+ self.header_lines = header_lines
87
+
88
+ if isThermoProfile:
89
+ self._expected_columns = {Labels.mz, Labels.abundance}
90
+
91
+ else:
92
+ self._expected_columns = {
93
+ Labels.mz,
94
+ Labels.abundance,
95
+ Labels.s2n,
96
+ Labels.rp,
97
+ }
98
+
99
+ self._delimiter = None
100
+
101
+ self.isCentroid = isCentroid
102
+
103
+ self.isThermoProfile = isThermoProfile
104
+
105
+ self.headerless = headerless
106
+
107
+ self._data_type = None
108
+
109
+ self.analyzer = analyzer
110
+
111
+ self.instrument_label = instrument_label
112
+
113
+ self.sample_name = sample_name
114
+
115
+ self._parameters = deepcopy(DataInputSetting())
116
+
117
+ @property
118
+ def parameters(self):
119
+ return self._parameters
120
+
121
+ @parameters.setter
122
+ def parameters(self, instance_DataInputSetting):
123
+ self._parameters = instance_DataInputSetting
124
+
125
+ def set_parameter_from_toml(self, parameters_path):
126
+ self._parameters = load_and_set_toml_parameters_class(
127
+ "DataInput", self.parameters, parameters_path=parameters_path
128
+ )
129
+
130
+ def set_parameter_from_json(self, parameters_path):
131
+ self._parameters = load_and_set_parameters_class(
132
+ "DataInput", self.parameters, parameters_path=parameters_path
133
+ )
134
+
135
+ @property
136
+ def data_type(self):
137
+ return self._data_type
138
+
139
+ @data_type.setter
140
+ def data_type(self, data_type):
141
+ self._data_type = data_type
142
+
143
+ @property
144
+ def delimiter(self):
145
+ return self._delimiter
146
+
147
+ @delimiter.setter
148
+ def delimiter(self, delimiter):
149
+ self._delimiter = delimiter
150
+
151
+ def encoding_detector(self, file_location) -> str:
152
+ """
153
+ Detects the encoding of a file.
154
+
155
+ Parameters
156
+ --------
157
+ file_location : str
158
+ The location of the file to be analyzed.
159
+
160
+ Returns
161
+ --------
162
+ str
163
+ The detected encoding of the file.
164
+ """
165
+
166
+ with file_location.open("rb") as rawdata:
167
+ result = chardet.detect(rawdata.read(10000))
168
+ return result["encoding"]
169
+
170
+ def set_data_type(self):
171
+ """
172
+ Set the data type and delimiter based on the file extension.
173
+
174
+ Raises
175
+ ------
176
+ TypeError
177
+ If the data type could not be automatically recognized.
178
+ """
179
+ if self.file_location.suffix == ".csv":
180
+ self.data_type = "txt"
181
+ self.delimiter = ","
182
+ elif self.file_location.suffix == ".txt":
183
+ self.data_type = "txt"
184
+ self.delimiter = "\t"
185
+ elif self.file_location.suffix == ".tsv":
186
+ self.data_type = "txt"
187
+ self.delimiter = "\t"
188
+ elif self.file_location.suffix == ".xlsx":
189
+ self.data_type = "excel"
190
+ elif self.file_location.suffix == ".ascii":
191
+ self.data_type = "txt"
192
+ self.delimiter = " "
193
+ elif self.file_location.suffix == ".pkl":
194
+ self.data_type = "dataframe"
195
+ elif self.file_location.suffix == ".pks":
196
+ self.data_type = "pks"
197
+ self.delimiter = " "
198
+ self.header_lines = 9
199
+ elif self.file_location.suffix == ".xml":
200
+ self.data_type = "xml"
201
+ # self.delimiter = None
202
+ # self.header_lines = None
203
+ elif self.file_location.suffix == ".xy":
204
+ self.data_type = "txt"
205
+ self.delimiter = " "
206
+ self.header_lines = None
207
+ else:
208
+ raise TypeError(
209
+ "Data type could not be automatically recognized for %s; please set data type and delimiter manually."
210
+ % self.file_location.name
211
+ )
212
+
213
+ def get_dataframe(self) -> DataFrame:
214
+ """
215
+ Get the data as a pandas DataFrame.
216
+
217
+ Returns
218
+ -------
219
+ pandas.DataFrame
220
+ The data as a pandas DataFrame.
221
+
222
+ Raises
223
+ ------
224
+ TypeError
225
+ If the data type is not supported.
226
+ """
227
+
228
+ if not self.data_type or not self.delimiter:
229
+ self.set_data_type()
230
+
231
+ if isinstance(self.file_location, S3Path):
232
+ data = BytesIO(self.file_location.open("rb").read())
233
+ else:
234
+ data = self.file_location
235
+
236
+ if self.data_type == "txt":
237
+ if self.headerless:
238
+ dataframe = read_csv(
239
+ data,
240
+ skiprows=self.header_lines,
241
+ delimiter=self.delimiter,
242
+ header=None,
243
+ names=["m/z", "I"],
244
+ encoding=self.encoding_detector(self.file_location),
245
+ engine="python",
246
+ )
247
+ else:
248
+ dataframe = read_csv(
249
+ data,
250
+ skiprows=self.header_lines,
251
+ delimiter=self.delimiter,
252
+ encoding=self.encoding_detector(self.file_location),
253
+ engine="python",
254
+ )
255
+
256
+ elif self.data_type == "pks":
257
+ # Predator .pks columns are positional: peak location (m/z), relative
258
+ # peak height (normalized 0-100), absolute abundance, resolving power,
259
+ # frequency, S/N. Use the absolute abundance as the intensity -- the
260
+ # relative peak height is per-spectrum normalized and not comparable
261
+ # across spectra, so it is named so header_translate drops it.
262
+ names = [
263
+ "m/z",
264
+ "Relative Abundance",
265
+ "Abundance",
266
+ "Resolving Power",
267
+ "Frequency",
268
+ "S/N"
269
+ ]
270
+
271
+
272
+ clean_data = []
273
+ with self.file_location.open() as maglabfile:
274
+ for i in maglabfile.readlines()[8:-1]:
275
+ clean_data.append(i.split())
276
+ dataframe = DataFrame(clean_data, columns=names)
277
+
278
+ elif self.data_type == "dataframe":
279
+ dataframe = read_pickle(data)
280
+
281
+ elif self.data_type == "excel":
282
+ dataframe = read_excel(data)
283
+
284
+ elif self.data_type == "xml":
285
+ dataframe = self.read_xml_peaks(data)
286
+
287
+ else:
288
+ raise TypeError("Data type %s is not supported" % self.data_type)
289
+
290
+ return dataframe
291
+
292
+ def load_settings(self, mass_spec_obj, output_parameters):
293
+ """
294
+ #TODO loading output parameters from json file is not functional
295
+ Load settings from a JSON file and apply them to the given mass_spec_obj.
296
+
297
+ Parameters
298
+ ----------
299
+ mass_spec_obj : MassSpec
300
+ The mass spectrum object to apply the settings to.
301
+
302
+ """
303
+ import json
304
+ import warnings
305
+
306
+ settings_file_path = self.file_location.with_suffix(".json")
307
+
308
+ if settings_file_path.exists():
309
+ self._parameters = load_and_set_parameters_class(
310
+ "DataInput", self._parameters, parameters_path=settings_file_path
311
+ )
312
+
313
+ load_and_set_parameters_ms(
314
+ mass_spec_obj, parameters_path=settings_file_path
315
+ )
316
+
317
+ else:
318
+ warnings.warn(
319
+ "auto settings loading is enabled but could not locate the file: %s. Please load the settings manually"
320
+ % settings_file_path
321
+ )
322
+
323
+ # TODO this will load the setting from SettingCoreMS.json
324
+ # coreMSHFD5 overrides this function to import the attrs stored in the h5 file
325
+ # loaded_settings = {}
326
+ # loaded_settings['MoleculaSearch'] = self.get_scan_group_attr_data(scan_index, time_index, 'MoleculaSearchSetting')
327
+ # loaded_settings['MassSpecPeak'] = self.get_scan_group_attr_data(scan_index, time_index, 'MassSpecPeakSetting')
328
+
329
+ # loaded_settings['MassSpectrum'] = self.get_scan_group_attr_data(scan_index, time_index, 'MassSpectrumSetting')
330
+ # loaded_settings['Transient'] = self.get_scan_group_attr_data(scan_index, time_index, 'TransientSetting')
331
+
332
+ def get_output_parameters(self, polarity: int, scan_index: int = 0) -> dict:
333
+ """
334
+ Get the output parameters for the mass spectrum.
335
+
336
+ Parameters
337
+ ----------
338
+ polarity : int
339
+ The polarity of the mass spectrum +1 or -1.
340
+ scan_index : int, optional
341
+ The index of the scan. Default is 0.
342
+
343
+ Returns
344
+ -------
345
+ dict
346
+ A dictionary containing the output parameters.
347
+
348
+ """
349
+ from copy import deepcopy
350
+
351
+ output_parameters = default_parameters(self.file_location)
352
+
353
+ if self.isCentroid:
354
+ output_parameters["label"] = Labels.corems_centroid
355
+ else:
356
+ output_parameters["label"] = Labels.bruker_profile
357
+
358
+ output_parameters["analyzer"] = self.analyzer
359
+
360
+ output_parameters["instrument_label"] = self.instrument_label
361
+
362
+ output_parameters["sample_name"] = self.sample_name
363
+
364
+ output_parameters["Aterm"] = None
365
+
366
+ output_parameters["Bterm"] = None
367
+
368
+ output_parameters["Cterm"] = None
369
+
370
+ output_parameters["polarity"] = polarity
371
+
372
+ # scan_number and rt will be need to lc ms====
373
+
374
+ output_parameters["mobility_scan"] = 0
375
+
376
+ output_parameters["mobility_rt"] = 0
377
+
378
+ output_parameters["scan_number"] = scan_index
379
+
380
+ output_parameters["rt"] = 0
381
+
382
+ return output_parameters
383
+
384
+ def clean_data_frame(self, dataframe):
385
+ """
386
+ Clean the input dataframe by removing columns that are not expected.
387
+
388
+ Parameters
389
+ ----------
390
+ pandas.DataFrame
391
+ The input dataframe to be cleaned.
392
+
393
+ """
394
+
395
+ for column_name in dataframe.columns:
396
+ expected_column_name = self.parameters.header_translate.get(column_name)
397
+ if expected_column_name not in self._expected_columns:
398
+ del dataframe[column_name]
399
+
400
+ def check_columns(self, header_labels: list[str]):
401
+ """
402
+ Check if the given header labels match the expected columns.
403
+
404
+ Parameters
405
+ ----------
406
+ header_labels : list
407
+ The header labels to be checked.
408
+
409
+ Raises
410
+ ------
411
+ Exception
412
+ If any expected column is not found in the header labels.
413
+ """
414
+ found_label = set()
415
+
416
+ for label in header_labels:
417
+ if not label in self._expected_columns:
418
+ user_column_name = self.parameters.header_translate.get(label)
419
+ if user_column_name in self._expected_columns:
420
+ found_label.add(user_column_name)
421
+ else:
422
+ found_label.add(label)
423
+
424
+ not_found = self._expected_columns - found_label
425
+
426
+ if len(not_found) > 0:
427
+ raise Exception(
428
+ "Please make sure to include the columns %s" % ", ".join(not_found)
429
+ )
430
+
431
+ def read_xml_peaks(self, data: str) -> DataFrame:
432
+ """
433
+ Read peaks from a Bruker .xml file and return a pandas DataFrame.
434
+
435
+ Parameters
436
+ ----------
437
+ data : str
438
+ The path to the .xml file.
439
+
440
+ Returns
441
+ -------
442
+ pandas.DataFrame
443
+ A DataFrame containing the peak data with columns: 'm/z', 'I', 'Resolving Power', 'Area', 'S/N', 'fwhm'.
444
+ """
445
+ from numpy import nan
446
+
447
+ with open(data, "r") as file:
448
+ content = file.readlines()
449
+ content = "".join(content)
450
+ bs_content = BeautifulSoup(content, features="xml")
451
+ peaks_xml = bs_content.find_all("pk")
452
+
453
+ # initialise lists of the peak variables
454
+ areas = []
455
+ fwhms = []
456
+ intensities = []
457
+ mzs = []
458
+ res = []
459
+ sn = []
460
+ # iterate through the peaks appending to each list
461
+ for peak in peaks_xml:
462
+ areas.append(
463
+ float(peak.get("a", nan))
464
+ ) # Use a default value if key 'a' is missing
465
+ fwhms.append(
466
+ float(peak.get("fwhm", nan))
467
+ ) # Use a default value if key 'fwhm' is missing
468
+ intensities.append(
469
+ float(peak.get("i", nan))
470
+ ) # Use a default value if key 'i' is missing
471
+ mzs.append(
472
+ float(peak.get("mz", nan))
473
+ ) # Use a default value if key 'mz' is missing
474
+ res.append(
475
+ float(peak.get("res", nan))
476
+ ) # Use a default value if key 'res' is missing
477
+ sn.append(
478
+ float(peak.get("sn", nan))
479
+ ) # Use a default value if key 'sn' is missing
480
+
481
+ # Compile pandas dataframe of these values
482
+ names = ["m/z", "I", "Resolving Power", "Area", "S/N", "fwhm"]
483
+ df = DataFrame(columns=names, dtype=float)
484
+ df["m/z"] = mzs
485
+ df["I"] = intensities
486
+ df["Resolving Power"] = res
487
+ df["Area"] = areas
488
+ df["S/N"] = sn
489
+ df["fwhm"] = fwhms
490
+ return df
491
+
492
+ def get_xml_polarity(self):
493
+ """
494
+ Get the polarity from an XML peaklist.
495
+
496
+ Returns
497
+ -------
498
+ int
499
+ The polarity of the XML peaklist. Returns -1 for negative polarity, +1 for positive polarity.
500
+
501
+ Raises
502
+ ------
503
+ Exception
504
+ If the data type is not XML peaklist in Bruker format or if the polarity is unhandled.
505
+ """
506
+
507
+ # Check its an actual xml
508
+ if not self.data_type or not self.delimiter:
509
+ self.set_data_type()
510
+
511
+ if isinstance(self.file_location, S3Path):
512
+ # data = self.file_location.open('rb').read()
513
+ data = BytesIO(self.file_location.open("rb").read())
514
+
515
+ else:
516
+ data = self.file_location
517
+
518
+ if self.data_type != "xml":
519
+ raise Exception("This function is only for XML peaklists (Bruker format)")
520
+
521
+ with open(data, "r") as file:
522
+ content = file.readlines()
523
+ content = "".join(content)
524
+ bs_content = BeautifulSoup(content, features="xml")
525
+ polarity = bs_content.find_all("ms_spectrum")[0]["polarity"]
526
+ if polarity == "-":
527
+ return -1
528
+ elif polarity == "+":
529
+ return +1
530
+ else:
531
+ raise Exception("Polarity %s unhandled" % polarity)
@@ -0,0 +1,161 @@
1
+ from io import BytesIO
2
+
3
+ import h5py
4
+ from s3path import S3Path
5
+
6
+ from corems.encapsulation.constant import Labels
7
+ from corems.encapsulation.factory.parameters import default_parameters
8
+ from corems.mass_spectrum.factory.MassSpectrumClasses import MassSpecProfile
9
+ from corems.mass_spectrum.input.baseClass import MassListBaseClass
10
+
11
+
12
+ class ReadHDF_BoosterMassSpectrum(MassListBaseClass):
13
+ """The ReadHDF_BoosterMassSpectrum class parses the mass spectrum data from an HDF file and generate a mass spectrum object.
14
+
15
+ Parameters
16
+ ----------
17
+ file_location : str
18
+ The path to the HDF file.
19
+ isCentroid : bool, optional
20
+ Specifies whether the mass spectrum is centroided or not. Default is False.
21
+
22
+ Attributes
23
+ ----------
24
+ polarity : int
25
+ The polarity of the mass spectrum.
26
+ h5pydata : h5py.File
27
+ The HDF file object.
28
+ scans : list
29
+ The list of scan names in the HDF file.
30
+
31
+ Methods
32
+ -------
33
+ * get_data_profile(mz, abundance, auto_process). Returns a MassSpecProfile object from the given m/z and abundance arrays.
34
+ * get_attr_data(scan, attr_srt). Returns the attribute value for the given scan and attribute name.
35
+ * get_polarity(file_location). Returns the polarity of the mass spectrum.
36
+ * get_mass_spectrum(auto_process). Returns the mass spectrum as a MassSpecProfile object.
37
+ * get_output_parameters(). Returns the default output parameters for the mass spectrum.
38
+ """
39
+
40
+ def __init__(self, file_location, isCentroid=False):
41
+ self.polarity = self.get_polarity(file_location)
42
+ super().__init__(file_location, isCentroid=False)
43
+
44
+ def get_data_profile(self, mz, abundance, auto_process) -> MassSpecProfile:
45
+ """
46
+ Returns a MassSpecProfile object from the given m/z and abundance arrays.
47
+
48
+ Parameters
49
+ ----------
50
+ mz : array_like
51
+ The m/z values.
52
+ abundance : array_like
53
+ The abundance values.
54
+ auto_process : bool
55
+ Specifies whether to automatically process the mass spectrum.
56
+
57
+ Returns
58
+ -------
59
+ MassSpecProfile
60
+ The MassSpecProfile object.
61
+
62
+ """
63
+ data_dict = {Labels.mz: mz, Labels.abundance: abundance}
64
+ output_parameters = self.get_output_parameters()
65
+ return MassSpecProfile(data_dict, output_parameters, auto_process=auto_process)
66
+
67
+ def get_attr_data(self, scan, attr_srt):
68
+ """
69
+ Returns the attribute value for the given scan and attribute name.
70
+
71
+ Parameters
72
+ ----------
73
+ scan : int
74
+ The scan index.
75
+ attr_srt : str
76
+ The attribute name.
77
+
78
+ Returns
79
+ -------
80
+ object
81
+ The attribute value.
82
+
83
+ """
84
+ return self.h5pydata[self.scans[scan]].attrs[attr_srt]
85
+
86
+ def get_polarity(self, file_location: str | S3Path) -> int:
87
+ """
88
+ Returns the polarity of the mass spectrum.
89
+
90
+ Parameters
91
+ ----------
92
+ file_location : str
93
+ The path to the HDF file.
94
+
95
+ Returns
96
+ -------
97
+ int
98
+ The polarity of the mass spectrum.
99
+
100
+ """
101
+ if isinstance(file_location, S3Path):
102
+ data = BytesIO(file_location.open("rb").read())
103
+ else:
104
+ data = file_location
105
+
106
+ self.h5pydata = h5py.File(data, "r")
107
+ self.scans = list(self.h5pydata.keys())
108
+
109
+ polarity = self.get_attr_data(0, "r_h_polarity")
110
+
111
+ if polarity == "negative scan":
112
+ return -1
113
+ else:
114
+ return +1
115
+
116
+ def get_mass_spectrum(self, auto_process=True) -> MassSpecProfile:
117
+ """
118
+ Returns the mass spectrum as a MassSpecProfile object.
119
+
120
+ Parameters
121
+ ----------
122
+ auto_process : bool, optional
123
+ Specifies whether to automatically process the mass spectrum. Default is True.
124
+
125
+ Returns
126
+ -------
127
+ MassSpecProfile
128
+ The MassSpecProfile object.
129
+
130
+ """
131
+ if len(self.scans) == 1:
132
+ booster_data = self.h5pydata[self.scans[0]]
133
+
134
+ if self.isCentroid:
135
+ raise NotImplementedError
136
+ else:
137
+ mz = booster_data[0]
138
+ abun = booster_data[1]
139
+ return self.get_data_profile(mz, abun, auto_process)
140
+
141
+ def get_output_parameters(self) -> dict:
142
+ """
143
+ Returns the default output parameters for the mass spectrum.
144
+
145
+ Returns
146
+ -------
147
+ dict
148
+ The default output parameters.
149
+
150
+ """
151
+ d_params = default_parameters(self.file_location)
152
+ d_params["polarity"] = self.polarity
153
+ d_params["filename_path"] = self.file_location
154
+ d_params["mobility_scan"] = 0
155
+ d_params["mobility_rt"] = 0
156
+ d_params["scan_number"] = 0
157
+ d_params["rt"] = self.get_attr_data(0, "r_h_start_time")
158
+ d_params["label"] = Labels.booster_profile
159
+ d_params["Aterm"] = self.get_attr_data(0, "r_cparams")[0]
160
+ d_params["Bterm"] = self.get_attr_data(0, "r_cparams")[1]
161
+ return d_params