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.
- corems/__init__.py +63 -0
- corems/chroma_peak/__init__.py +0 -0
- corems/chroma_peak/calc/ChromaPeakCalc.py +480 -0
- corems/chroma_peak/calc/__init__.py +0 -0
- corems/chroma_peak/calc/subset.py +196 -0
- corems/chroma_peak/factory/__init__.py +0 -0
- corems/chroma_peak/factory/chroma_peak_classes.py +1178 -0
- corems/encapsulation/__init__.py +0 -0
- corems/encapsulation/constant.py +1283 -0
- corems/encapsulation/factory/__init__.py +0 -0
- corems/encapsulation/factory/parameters.py +392 -0
- corems/encapsulation/factory/processingSetting.py +1244 -0
- corems/encapsulation/input/__init__.py +0 -0
- corems/encapsulation/input/parameter_from_json.py +579 -0
- corems/encapsulation/output/__init__.py +0 -0
- corems/encapsulation/output/parameter_to_dict.py +142 -0
- corems/encapsulation/output/parameter_to_json.py +332 -0
- corems/mass_spectra/__init__.py +0 -0
- corems/mass_spectra/calc/GC_Calc.py +84 -0
- corems/mass_spectra/calc/GC_Deconvolution.py +558 -0
- corems/mass_spectra/calc/GC_RI_Calibration.py +44 -0
- corems/mass_spectra/calc/MZSearch.py +249 -0
- corems/mass_spectra/calc/SignalProcessing.py +656 -0
- corems/mass_spectra/calc/__init__.py +0 -0
- corems/mass_spectra/calc/lc_calc.py +5790 -0
- corems/mass_spectra/calc/lc_calc_operations.py +1127 -0
- corems/mass_spectra/factory/GC_Class.py +791 -0
- corems/mass_spectra/factory/__init__.py +0 -0
- corems/mass_spectra/factory/chromat_data.py +51 -0
- corems/mass_spectra/factory/lc_class.py +2721 -0
- corems/mass_spectra/input/__init__.py +0 -0
- corems/mass_spectra/input/andiNetCDF.py +200 -0
- corems/mass_spectra/input/boosterHDF5.py +216 -0
- corems/mass_spectra/input/brukerSolarix.py +153 -0
- corems/mass_spectra/input/brukerSolarix_utils.py +73 -0
- corems/mass_spectra/input/corems_hdf5.py +1710 -0
- corems/mass_spectra/input/massList.py +133 -0
- corems/mass_spectra/input/mzml.py +668 -0
- corems/mass_spectra/input/parserbase.py +239 -0
- corems/mass_spectra/input/rawFileReader.py +1839 -0
- corems/mass_spectra/output/__init__.py +0 -0
- corems/mass_spectra/output/export.py +2800 -0
- corems/mass_spectrum/__init__.py +0 -0
- corems/mass_spectrum/calc/AutoRecalibration.py +237 -0
- corems/mass_spectrum/calc/Calibration.py +602 -0
- corems/mass_spectrum/calc/CalibrationCalc.py +253 -0
- corems/mass_spectrum/calc/KendrickGroup.py +239 -0
- corems/mass_spectrum/calc/MassErrorPrediction.py +436 -0
- corems/mass_spectrum/calc/MassSpectrumCalc.py +303 -0
- corems/mass_spectrum/calc/MeanResolvingPowerFilter.py +212 -0
- corems/mass_spectrum/calc/NoiseCalc.py +371 -0
- corems/mass_spectrum/calc/NoiseCalc_Bayes.py +93 -0
- corems/mass_spectrum/calc/PeakPicking.py +994 -0
- corems/mass_spectrum/calc/__init__.py +0 -0
- corems/mass_spectrum/factory/MassSpectrumClasses.py +1753 -0
- corems/mass_spectrum/factory/__init__.py +0 -0
- corems/mass_spectrum/input/__init__.py +0 -0
- corems/mass_spectrum/input/baseClass.py +531 -0
- corems/mass_spectrum/input/boosterHDF5.py +161 -0
- corems/mass_spectrum/input/coremsHDF5.py +475 -0
- corems/mass_spectrum/input/massList.py +402 -0
- corems/mass_spectrum/input/numpyArray.py +133 -0
- corems/mass_spectrum/output/__init__.py +0 -0
- corems/mass_spectrum/output/export.py +841 -0
- corems/molecular_formula/__init__.py +0 -0
- corems/molecular_formula/calc/MolecularFormulaCalc.py +885 -0
- corems/molecular_formula/calc/__init__.py +0 -0
- corems/molecular_formula/factory/MolecularFormulaFactory.py +895 -0
- corems/molecular_formula/factory/__init__.py +0 -0
- corems/molecular_formula/input/__init__.py +0 -0
- corems/molecular_formula/input/masslist_ref.py +355 -0
- corems/molecular_id/__init__.py +0 -0
- corems/molecular_id/calc/ClusterFilter.py +251 -0
- corems/molecular_id/calc/MolecularFilter.py +122 -0
- corems/molecular_id/calc/SpectralSimilarity.py +632 -0
- corems/molecular_id/calc/__init__.py +0 -0
- corems/molecular_id/calc/math_distance.py +1637 -0
- corems/molecular_id/data/FAMES_REF.msp +980 -0
- corems/molecular_id/data/PNNLMetV20191015.msp +157267 -0
- corems/molecular_id/factory/EI_SQL.py +650 -0
- corems/molecular_id/factory/MolecularLookupTable.py +914 -0
- corems/molecular_id/factory/__init__.py +0 -0
- corems/molecular_id/factory/classification.py +884 -0
- corems/molecular_id/factory/lipid_molecular_metadata.py +50 -0
- corems/molecular_id/factory/molecularSQL.py +827 -0
- corems/molecular_id/factory/spectrum_search_results.py +119 -0
- corems/molecular_id/input/__init__.py +0 -0
- corems/molecular_id/input/nistMSI.py +148 -0
- corems/molecular_id/search/__init__.py +0 -0
- corems/molecular_id/search/compoundSearch.py +214 -0
- corems/molecular_id/search/database_interfaces.py +1527 -0
- corems/molecular_id/search/findOxygenPeaks.py +330 -0
- corems/molecular_id/search/lcms_spectral_search.py +348 -0
- corems/molecular_id/search/molecularFormulaSearch.py +1117 -0
- corems/molecular_id/search/priorityAssignment.py +723 -0
- corems/ms_peak/__init__.py +0 -0
- corems/ms_peak/calc/MSPeakCalc.py +1010 -0
- corems/ms_peak/calc/__init__.py +0 -0
- corems/ms_peak/factory/MSPeakClasses.py +542 -0
- corems/ms_peak/factory/__init__.py +0 -0
- corems/transient/__init__.py +0 -0
- corems/transient/calc/TransientCalc.py +362 -0
- corems/transient/calc/__init__.py +0 -0
- corems/transient/factory/TransientClasses.py +457 -0
- corems/transient/factory/__init__.py +0 -0
- corems/transient/input/__init__.py +0 -0
- corems/transient/input/brukerSolarix.py +461 -0
- corems/transient/input/midasDatFile.py +172 -0
- corems-4.0.0.dist-info/METADATA +475 -0
- corems-4.0.0.dist-info/RECORD +171 -0
- corems-4.0.0.dist-info/WHEEL +5 -0
- corems-4.0.0.dist-info/licenses/LICENSE +22 -0
- corems-4.0.0.dist-info/top_level.txt +4 -0
- examples/archive/scripts/CoreMS_tutorial.py +94 -0
- examples/archive/scripts/DI HR-MS Halogens Bruker.py +196 -0
- examples/archive/scripts/DI HR-MS MassList.py +385 -0
- examples/archive/scripts/GC-MS MetabRef.py +213 -0
- examples/archive/scripts/GC-MS NetCDF.py +217 -0
- examples/archive/scripts/HR-MS Thermo Raw 21T.py +136 -0
- examples/archive/scripts/LC-ICPMS_metal_peaks.py +297 -0
- examples/archive/scripts/LCMS-Thermo.py +460 -0
- examples/archive/scripts/LCMS_isotopes.py +283 -0
- examples/archive/scripts/MSParams_example.py +21 -0
- examples/archive/scripts/Molecular Formula Data Aggreation.py +84 -0
- examples/archive/scripts/Single Mz Search.py +69 -0
- examples/test_notebooks.py +145 -0
- ext_lib/ChemstationMSFileReader.dll +0 -0
- ext_lib/ChemstationMSFileReader.xml +126 -0
- ext_lib/RawFileReaderLicense.doc +0 -0
- ext_lib/ThermoFisher.CommonCore.BackgroundSubtraction.dll +0 -0
- ext_lib/ThermoFisher.CommonCore.BackgroundSubtraction.xml +2307 -0
- ext_lib/ThermoFisher.CommonCore.Data.dll +0 -0
- ext_lib/ThermoFisher.CommonCore.Data.xml +28974 -0
- ext_lib/ThermoFisher.CommonCore.MassPrecisionEstimator.dll +0 -0
- ext_lib/ThermoFisher.CommonCore.MassPrecisionEstimator.xml +241 -0
- ext_lib/ThermoFisher.CommonCore.RawFileReader.dll +0 -0
- ext_lib/ThermoFisher.CommonCore.RawFileReader.xml +31174 -0
- ext_lib/__init__.py +0 -0
- ext_lib/dotnet/OpenMcdf.Extensions.dll +0 -0
- ext_lib/dotnet/OpenMcdf.dll +0 -0
- ext_lib/dotnet/OpenMcdf.xml +1154 -0
- ext_lib/dotnet/System.IO.FileSystem.AccessControl.dll +0 -0
- ext_lib/dotnet/System.IO.FileSystem.AccessControl.xml +506 -0
- ext_lib/dotnet/System.Security.AccessControl.dll +0 -0
- ext_lib/dotnet/System.Security.AccessControl.xml +2043 -0
- ext_lib/dotnet/System.Security.Principal.Windows.dll +0 -0
- ext_lib/dotnet/System.Security.Principal.Windows.xml +1011 -0
- ext_lib/dotnet/ThermoFisher.CommonCore.BackgroundSubtraction.dll +0 -0
- ext_lib/dotnet/ThermoFisher.CommonCore.BackgroundSubtraction.xml +2307 -0
- ext_lib/dotnet/ThermoFisher.CommonCore.Data.dll +0 -0
- ext_lib/dotnet/ThermoFisher.CommonCore.Data.xml +29148 -0
- ext_lib/dotnet/ThermoFisher.CommonCore.MassPrecisionEstimator.dll +0 -0
- ext_lib/dotnet/ThermoFisher.CommonCore.MassPrecisionEstimator.xml +241 -0
- ext_lib/dotnet/ThermoFisher.CommonCore.RawFileReader.dll +0 -0
- ext_lib/dotnet/ThermoFisher.CommonCore.RawFileReader.xml +31492 -0
- ext_lib/version +18 -0
- support_code/atom_parsers/AtomsDescription.py +359 -0
- support_code/atom_parsers/CreateAtomsDescription.py +56 -0
- support_code/nmdc/filefinder.py +90 -0
- support_code/nmdc/lipidomics/lipidomics_workflow.py +748 -0
- support_code/nmdc/lipidomics/manifest_examples.py +49 -0
- support_code/nmdc/metabolomics/gcms_workflow.py +158 -0
- support_code/nmdc/metabolomics/lcms_metabolomics_targeted_search.py +59 -0
- support_code/nmdc/metabolomics/lcms_metabolomics_workflow.py +248 -0
- support_code/nmdc/metabolomics/metabolomics_collection.py +628 -0
- support_code/nmdc/metadata/dms_api.py +42 -0
- support_code/nmdc/nom/archived_scripts/nmdc_metadata_gen.py +288 -0
- support_code/nmdc/nom/archived_scripts/nom_grow_workflow.py +209 -0
- support_code/nmdc/nom/nom_workflow.py +312 -0
- support_code/windows_only_importers/BrukerCompassXtract.py +180 -0
- 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
|