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,461 @@
1
+ __author__ = "Yuri E. Corilo"
2
+ __date__ = "Jun 12, 2019"
3
+ from copy import deepcopy
4
+ from datetime import datetime
5
+ from pathlib import Path
6
+ from xml.dom import minidom
7
+
8
+ from numpy import dtype, float32, float64, frombuffer, fromfile, fromstring, genfromtxt
9
+ from s3path import S3Path
10
+
11
+ from corems.encapsulation.factory.parameters import default_parameters
12
+ from corems.transient.factory.TransientClasses import Transient
13
+ from corems.mass_spectra.input.brukerSolarix_utils import get_scan_attributes
14
+
15
+
16
+ class ReadBrukerSolarix(object):
17
+ """A class used to Read a single Transient from Bruker's FT-MS acquisition station (fid, or ser)
18
+
19
+ Parameters
20
+ ----------
21
+ d_directory_location : str
22
+ the full path of the .d folder
23
+
24
+ Attributes
25
+ --------
26
+ d_directory_location : str
27
+ the full path of the .d folder
28
+ file_location : str
29
+ the full path of the .d folder
30
+ parameter_filename_location : str
31
+ the full path of the apexAcquisition.method file
32
+ transient_data_path : str
33
+ the full path of the fid or ser file
34
+ scan_attr : str
35
+ the full path of the scan.xml file
36
+
37
+
38
+ Methods
39
+ -------
40
+ * get_transient().
41
+ Read the data and settings returning a Transient class
42
+ * get_scan_attr().
43
+ Read the scan retention times, TIC values and scan indices.
44
+ * locate_file(folder, type_file_name).
45
+ Find the full path of a specific file within the acquisition .d folder or subfolders
46
+ * parse_parameters(parameters_filename).
47
+ Open the given file and retrieve all parameters from apexAcquisition.method
48
+ * fix_freq_limits(d_parameters).
49
+ Read and set the correct frequency limits for the spectrum
50
+ * get_excite_sweep_range(filename).
51
+ Determine excitation sweep range from ExciteSweep file
52
+
53
+ """
54
+
55
+ def __enter__(self):
56
+ return self.get_transient()
57
+
58
+ def __exit__(self, exc_type, exc_val, exc_tb):
59
+ return False
60
+
61
+ def __init__(self, d_directory_location):
62
+ if isinstance(d_directory_location, str):
63
+ d_directory_location = Path(d_directory_location)
64
+
65
+ if not d_directory_location.exists():
66
+ raise FileNotFoundError("File does not exist: " + str(d_directory_location))
67
+
68
+ self.d_directory_location = d_directory_location
69
+
70
+ self.file_location = d_directory_location
71
+
72
+ try:
73
+ self.parameter_filename_location = self.locate_file(
74
+ d_directory_location, "apexAcquisition.method"
75
+ )
76
+ self.transient_data_path = d_directory_location / "fid"
77
+
78
+ if not self.transient_data_path.exists():
79
+ self.transient_data_path = d_directory_location / "ser"
80
+
81
+ if not self.transient_data_path.exists():
82
+ raise FileNotFoundError("Could not locate transient data")
83
+
84
+ else:
85
+ # get scan attributes
86
+ self.scan_attr = d_directory_location / "scan.xml"
87
+ self.imaging_info_attr = d_directory_location / "ImagingInfo.xml"
88
+
89
+
90
+ except:
91
+ raise FileExistsError(
92
+ "%s does not seem to be a valid Solarix Mass Spectrum"
93
+ % (d_directory_location)
94
+ )
95
+
96
+ def get_scan_attr(self):
97
+ """Function to get the scan retention times, TIC values and scan indices.
98
+
99
+ Gets information from scan.xml file in the bruker .d folder.
100
+ Note this file is only present in some .d format - e.g. for imaging mode data, it is not present.
101
+
102
+ Returns
103
+ -------
104
+ dict_scan_rt_tic : dict
105
+ a dictionary with scan number as key and rt and tic as values
106
+ """
107
+
108
+ return get_scan_attributes(self.scan_attr, self.imaging_info_attr)
109
+
110
+
111
+ def get_transient(self, scan_number=1):
112
+ """Function to get the transient data and parameters from a Bruker Solarix .d folder.
113
+
114
+ Parameters
115
+ ----------
116
+ scan_number : int
117
+ the scan number to be read. Default is 1.
118
+
119
+ Returns
120
+ -------
121
+ Transient
122
+ a transient object
123
+ """
124
+
125
+ file_d_params = self.parse_parameters(self.parameter_filename_location)
126
+
127
+ self.fix_freq_limits(file_d_params)
128
+
129
+ from sys import platform
130
+
131
+ if platform == "win32":
132
+ # Windows...
133
+ dt = dtype("l")
134
+ else:
135
+ dt = dtype("i")
136
+
137
+ # get rt, scan, and tic from scan.xml file, otherwise using 0 defaults values
138
+
139
+ output_parameters = deepcopy(default_parameters(self.d_directory_location))
140
+
141
+ if self.transient_data_path.name == "ser":
142
+ dict_scan_rt_tic = self.get_scan_attr()
143
+
144
+ output_parameters["scan_number"] = scan_number
145
+
146
+ output_parameters["rt"] = dict_scan_rt_tic.get(scan_number)[0]
147
+
148
+ output_parameters["tic"] = dict_scan_rt_tic.get(scan_number)[1]
149
+
150
+ output_parameters["analyzer"] = "ICR"
151
+
152
+ output_parameters["label"] = "Bruker_Frequency"
153
+
154
+ output_parameters["Aterm"] = float(file_d_params.get("ML1"))
155
+
156
+ output_parameters["Bterm"] = float(file_d_params.get("ML2"))
157
+
158
+ output_parameters["Cterm"] = float(file_d_params.get("ML3"))
159
+
160
+ output_parameters["exc_high_freq"] = float(file_d_params.get("EXC_Freq_High"))
161
+
162
+ output_parameters["exc_low_freq"] = float(file_d_params.get("EXC_Freq_Low"))
163
+ try:
164
+ output_parameters["qpd_enabled"] = float(file_d_params.get("QPD_Enabled"))
165
+ except TypeError: # for older datasets which dont have this variable
166
+ output_parameters["qpd_enabled"] = 0
167
+
168
+ output_parameters["mw_low"] = float(file_d_params.get("MW_low"))
169
+
170
+ output_parameters["mw_high"] = float(file_d_params.get("MW_high"))
171
+
172
+ output_parameters["bandwidth"] = float(file_d_params.get("SW_h"))
173
+
174
+ output_parameters["number_data_points"] = int(file_d_params.get("TD"))
175
+
176
+ output_parameters["polarity"] = str(file_d_params.get("Polarity"))
177
+
178
+ output_parameters["acquisition_time"] = file_d_params.get("acquisition_time")
179
+
180
+ data_points = int(file_d_params.get("TD"))
181
+
182
+ scan = output_parameters["scan_number"]
183
+ from io import BytesIO
184
+
185
+ if self.transient_data_path.name == "ser":
186
+ if isinstance(self.transient_data_path, S3Path):
187
+ databin = BytesIO(self.transient_data_path.open("rb").read())
188
+
189
+ else:
190
+ databin = self.transient_data_path.open("rb")
191
+
192
+ databin.seek((scan - 1) * 4 * data_points)
193
+ # read scan data and parse to 32int struct
194
+ data = frombuffer(databin.read(4 * data_points), dtype=dt)
195
+
196
+ else:
197
+ if isinstance(self.transient_data_path, S3Path):
198
+ data = frombuffer(self.transient_data_path.open("rb").read(), dtype=dt)
199
+ else:
200
+ data = fromfile(self.transient_data_path, dtype=dt)
201
+
202
+ return Transient(data, output_parameters)
203
+
204
+ # for key, values in default_parameters.items():
205
+ # print(key, values)
206
+ def fix_freq_limits(self, d_parameters):
207
+ """Function to read and set the correct frequency limits for the spectrum
208
+
209
+ Notes
210
+ --------
211
+ This is using the excitation limits from the apexAcquisition.method file,
212
+ which may not match the intended detection limits in edge cases.
213
+ In default acquisitions, excitation and detection are the same.
214
+ But, they may not be in some cases with selective excitation, custom excite waveforms, or in 2DMS applications.
215
+
216
+ Parameters
217
+ ----------
218
+ d_parameters : dict
219
+ a dictionary with the parameters from the apexAcquisition.method file
220
+ """
221
+
222
+ highfreq = float(d_parameters.get("EXC_Freq_High"))
223
+
224
+ lowfreq = float(d_parameters.get("EXC_Freq_Low"))
225
+
226
+ # CR for compatibility with Apex format as there is no EXciteSweep file
227
+ if not highfreq and lowfreq:
228
+ excitation_sweep_filelocation = self.locate_file(
229
+ self.d_directory_location, "ExciteSweep"
230
+ )
231
+ lowfreq, highfreq = self.get_excite_sweep_range(
232
+ excitation_sweep_filelocation
233
+ )
234
+ d_parameters["EXC_Freq_High"] = highfreq
235
+ d_parameters["EXC_Freq_Low"] = lowfreq
236
+
237
+ @staticmethod
238
+ def get_excite_sweep_range(filename):
239
+ """Function to determine excitation sweep range from ExciteSweep file
240
+
241
+ This looks at the first and last rows of the ExciteSweep file to determine the excitation frequency range.
242
+ Note that this assumes the excitation sweep was linear and the first and last rows are the lowest and highest frequencies.
243
+ This is presumably always true, but again may be incorrect for edge cases with custom excitation waveforms.
244
+
245
+ Parameters
246
+ ----------
247
+ filename : str
248
+ the full path to the ExciteSweep file
249
+
250
+ """
251
+ ExciteSweep_lines = genfromtxt(filename, comments="*", delimiter="\n")
252
+ # CR ready if we need the full array
253
+ highfreq = fromstring(ExciteSweep_lines[0])
254
+ lowfreq = fromstring(ExciteSweep_lines[-1])
255
+
256
+ return lowfreq[0], highfreq[0]
257
+
258
+ @staticmethod
259
+ def locate_file(folder, type_file_name="apexAcquisition.method"):
260
+ """Function to locate a file in a folder
261
+
262
+ Find the full path of a specific file within the acquisition .d folder or subfolders
263
+
264
+ Parameters
265
+ ----------
266
+ folder : str
267
+ the full path to the folder
268
+ type_file_name : str
269
+ the name of the file to be located
270
+ Expected options: ExciteSweep or apexAcquisition.method
271
+
272
+ Returns
273
+ -------
274
+ str
275
+ the full path to the file
276
+
277
+ Notes
278
+ -----
279
+ adapted from code from SPIKE library, https://github.com/spike-project/spike
280
+
281
+ """
282
+
283
+ from pathlib import Path
284
+
285
+ # directory_location = folder.glob( '**/*apexAcquisition.method')
286
+ directory_location = folder.glob("**/*" + type_file_name)
287
+ result = list(directory_location)
288
+ if len(result) > 1:
289
+ raise Exception(
290
+ "You have more than 1 %s file in the %s folder, using the first one"
291
+ % (type_file_name, folder)
292
+ )
293
+
294
+ elif len(result) == 0:
295
+ raise Exception(
296
+ "You don't have any %s file in the %s folder, please double check the path"
297
+ % (type_file_name, folder)
298
+ )
299
+
300
+ return result[0]
301
+
302
+ @staticmethod
303
+ def parse_parameters(parameters_filename):
304
+ """Function to parse the parameters from apexAcquisition.method file
305
+
306
+ Open the given file and retrieve all parameters from apexAcquisition.method
307
+ None is written when no value for value is found
308
+
309
+ structure : <param name = "AMS_ActiveExclusion"><value>0</value></param>
310
+
311
+ Parameters
312
+ ----------
313
+ parameters_filename : str
314
+ the full path to the apexAcquisition.method file
315
+
316
+ Returns
317
+ -------
318
+ dict
319
+ a dictionary with the parameters and values
320
+
321
+ Notes
322
+ -----
323
+ Adapted from code from SPIKE library, https://github.com/spike-project/spike.
324
+ Code may not handle all possible parameters, but should be sufficient for most common use cases
325
+ """
326
+
327
+ # TODO: change to beautiful soup xml parsing
328
+
329
+ xmldoc = minidom.parse(parameters_filename.open())
330
+
331
+ x = xmldoc.documentElement
332
+ parameter_dict = {}
333
+ children = x.childNodes
334
+ for child in children:
335
+ # print( child.node)
336
+ if child.nodeName == "methodmetadata":
337
+ sections = child.childNodes
338
+ for section in sections:
339
+ for element in section.childNodes:
340
+ if element.nodeName == "date":
341
+ # if element.nodeName == "primarykey":
342
+
343
+ date_time_str = element.childNodes[0].nodeValue
344
+ # parameter_dict["acquisition_time"] = pd.to_datetime(date_time_str, infer_datetime_format=True).to_pydatetime()
345
+ parameter_dict["acquisition_time"] = datetime.strptime(
346
+ date_time_str, "%b_%d_%Y %H:%M:%S.%f"
347
+ )
348
+
349
+ if child.nodeName == "reportinfo":
350
+ sections = child.childNodes
351
+ for section in sections:
352
+ if section.nodeName == "section":
353
+ if section.getAttribute("title") == "Main":
354
+ for element in section.childNodes:
355
+ if element.nodeName == "section":
356
+ if element.getAttribute("title") == "Polarity":
357
+ if (
358
+ str(
359
+ element.childNodes[1].getAttribute(
360
+ "value"
361
+ )
362
+ )
363
+ == "Negative"
364
+ ):
365
+ parameter_dict["Polarity"] = -1
366
+ else:
367
+ parameter_dict["Polarity"] = 1
368
+
369
+ if child.nodeName == "paramlist":
370
+ params = child.childNodes
371
+ for param in params:
372
+ # print( param.nodeName)
373
+ if param.nodeName == "param":
374
+ paramenter_label = str(param.getAttribute("name"))
375
+ for element in param.childNodes:
376
+ if element.nodeName == "value":
377
+ try:
378
+ parameter_value = str(element.firstChild.toxml())
379
+ # print v
380
+ except:
381
+ parameter_value = None
382
+
383
+ parameter_dict[paramenter_label] = parameter_value
384
+
385
+ return parameter_dict
386
+
387
+ def parse_sqlite(self, sqlite_filename="chromatography-data.sqlite"):
388
+ """ """
389
+ import sqlite3
390
+
391
+ def read_sqlite_file(file_path, table_name):
392
+ """
393
+ Read data from a SQLite database file and return it as a list of tuples
394
+
395
+ Parameters
396
+ ----------
397
+ file_path : str
398
+ the full path to the SQLite database file
399
+ table_name : str
400
+ the name of the table to be read
401
+
402
+ Returns
403
+ -------
404
+ list
405
+ a list of tuples with the data from the table
406
+ """
407
+ # Connect to the SQLite database file
408
+ conn = sqlite3.connect(file_path)
409
+ cursor = conn.cursor()
410
+
411
+ # Execute a query to select data from a table (replace 'table_name' with your table's name)
412
+ query = f"SELECT * FROM {table_name}"
413
+ cursor.execute(query)
414
+
415
+ # Fetch all rows from the result set
416
+ rows = cursor.fetchall()
417
+ stream = []
418
+ # Print or process the fetched rows
419
+ for row in rows:
420
+ stream.append(row)
421
+ # print(row) # Print each row, you can also process it differently
422
+
423
+ # Close the cursor and the connection
424
+ cursor.close()
425
+ conn.close()
426
+ return stream
427
+
428
+ def parse_binary(binary, type):
429
+ """
430
+ Parse binary data from the sqlite data streams
431
+ """
432
+ if type == "double":
433
+ data = frombuffer(binary, dtype=float64)
434
+ elif type == "float":
435
+ data = frombuffer(binary, dtype=float32)
436
+ return data
437
+
438
+ sqlite_filelocation = self.locate_file(
439
+ self.d_directory_location, sqlite_filename
440
+ )
441
+ table_name = "TraceSources"
442
+ trace_sources = read_sqlite_file(sqlite_filelocation, table_name)
443
+ table_name = "TraceChunks"
444
+ trace_chunks = read_sqlite_file(sqlite_filelocation, table_name)
445
+ times = []
446
+ values = []
447
+ trace_type = {}
448
+
449
+ for index, source in enumerate(trace_sources):
450
+ trace_id = source[0]
451
+ trace_type[source[1]] = {"times": [], "values": []}
452
+ for index, chunk in enumerate(trace_chunks):
453
+ id = chunk[0]
454
+ times = parse_binary(chunk[1], "double")
455
+ values = parse_binary(chunk[2], "float")
456
+ for time, value in zip(times, values):
457
+ if source[0] == id:
458
+ trace_type[source[1]]["times"].append(time)
459
+ trace_type[source[1]]["values"].append(value)
460
+
461
+ return trace_type
@@ -0,0 +1,172 @@
1
+ from os import path
2
+
3
+ from numpy import dtype, fromfile
4
+
5
+
6
+ __author__ = "Yuri E. Corilo"
7
+ __date__ = "Jun 19, 2019"
8
+
9
+
10
+ class ReadMidasDatFile:
11
+ """[Not Implemented] Reads MIDAS .dat files (binary transient data)
12
+
13
+ This class will read .dat binary format transient data, e.g. midas format from Predator or Thermo datastations
14
+ This code is not yet implemented and is not fully functional.
15
+
16
+ Parameters
17
+ ----------
18
+ filename_path : str
19
+ The path to the .dat file
20
+
21
+ Attributes
22
+ ----------
23
+ filename_path : str
24
+ The path to the .dat file
25
+ d_params : dict
26
+ A dictionary with the parameters of the .dat file
27
+ transient_data : numpy.ndarray
28
+ The transient data
29
+
30
+ Methods
31
+ -------
32
+ * read_file().
33
+ Reads the .dat file and returns the transient data and the parameters
34
+ * get_transient_data(data_file, d_params).
35
+ Reads the transient data from the .dat file
36
+ * parse_parameter(f).
37
+ Parses the parameters from the .dat file
38
+
39
+ Raises
40
+ ------
41
+ NotImplementedError
42
+ This class is not yet implemented.
43
+
44
+ """
45
+
46
+ def __init__(self, filename_path):
47
+ raise NotImplementedError(
48
+ "This class is not yet implemented, if you want to use it please contact the author at corilo@pnnl.gov or feel free to implement it"
49
+ )
50
+ if not path.isfile(filename_path):
51
+ raise Exception("File does not exist: " + filename_path)
52
+
53
+ self.filename_path = filename_path
54
+
55
+ def read_file(self):
56
+ """Reads the .dat file and returns the transient data and the parameters
57
+
58
+ Returns
59
+ -------
60
+ transient_data : numpy.ndarray
61
+ The transient data
62
+ d_params : dict
63
+ A dictionary with the parameters of the .dat file
64
+
65
+ """
66
+ data_file = open(self.filename_path, "rb")
67
+
68
+ # modo_de_ions = "POSITIVE ION MODE"
69
+ d_params = self.parse_parameters(self.parameter_filename_location)
70
+
71
+ transient_data = self.get_transient_data(data_file, d_params, d_params)
72
+
73
+ return transient_data, d_params
74
+
75
+ def get_transient_data(self, data_file, d_params):
76
+ """Reads the transient data from the .dat file
77
+
78
+ Parameters
79
+ ----------
80
+ data_file : file
81
+ The .dat file
82
+ d_params : dict
83
+ A dictionary with the parameters of the .dat file
84
+
85
+ Returns
86
+ -------
87
+ myarray : numpy.ndarray
88
+ The transient data
89
+ """
90
+
91
+ # dt = np.dtype('<f')
92
+ if d_params.get("storage_type").split()[0] == "int":
93
+ dt = dtype("i2")
94
+
95
+ else:
96
+ dt = dtype("<f")
97
+ # dt = np.dtype(int)
98
+
99
+ myarray = fromfile(data_file, dtype=dt)
100
+
101
+ data_file.close()
102
+
103
+ if d_params.get("storage_type").split()[0] == "int":
104
+ return myarray * d_params.get("VoltageScale")
105
+
106
+ else:
107
+ return myarray
108
+
109
+ def parse_parameter(self, f):
110
+ """Parses the parameters from the .dat file
111
+
112
+ Parameters
113
+ ----------
114
+ f : file
115
+ The .dat file
116
+
117
+ Returns
118
+ -------
119
+ output_parameters : dict
120
+ A dictionary with the parameters of the .dat file
121
+ """
122
+
123
+ output_parameters = {}
124
+ output_parameters["filename_path"] = self.d_directory_location
125
+
126
+ line = f.readline()
127
+
128
+ while line != "Data:\n":
129
+ if line[0:8] == "highfreq":
130
+ final_frequency = float(line.split(":")[1])
131
+ output_parameters["exc_high_freq"] = final_frequency
132
+
133
+ elif line[0:7] == "lowfreq":
134
+ initial_frequency = float(line.split(":")[1])
135
+ output_parameters["exc_low_freq"] = initial_frequency
136
+
137
+ elif line[0:9] == "sweeprate":
138
+ sweeprate = float(line.split(":")[1])
139
+
140
+ output_parameters["sweeprate"] = sweeprate
141
+
142
+ elif line[0:13] == "Source Coeff0":
143
+ Acoef = float(line.split(":")[1])
144
+ output_parameters["Aterm"] = Acoef
145
+ # print f.readline()
146
+ elif line[0:13] == "Source Coeff1":
147
+ output_parameters["Bterm"] = "Bcoef"
148
+
149
+ elif line[0:13] == "Voltage Scale":
150
+ voltage_scale = float(line.split(":")[1])
151
+ output_parameters["VoltageScale"] = voltage_scale
152
+
153
+ elif line[0:9] == "Bandwidth":
154
+ bandwidth = float(line.split(":")[1])
155
+ output_parameters["bandwidth"] = bandwidth
156
+
157
+ elif line[0:11] == "Data Points":
158
+ datapoints = float(line.split(":")[1])
159
+ output_parameters["number_data_points"] = datapoints
160
+
161
+ elif line[0:12] == "Storage Type":
162
+ storage_type = line.split(":")[1]
163
+ output_parameters["storage_type"] = storage_type
164
+
165
+ elif line[0:12] == "Trap Voltage":
166
+ trap_voltage = float(line.split(":")[1])
167
+ # Bcoef = Bcoef*trap_voltage
168
+ output_parameters["trap_voltage"] = trap_voltage
169
+
170
+ line = f.readline()
171
+
172
+ return output_parameters