chromaquant 0.4.0__py3-none-any.whl → 0.5.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 (63) hide show
  1. chromaquant/__init__.py +9 -2
  2. chromaquant/data/__init__.py +14 -0
  3. chromaquant/data/breakdown.py +430 -0
  4. chromaquant/data/dataset.py +195 -0
  5. chromaquant/data/table.py +412 -0
  6. chromaquant/data/value.py +215 -0
  7. chromaquant/formula/__init__.py +13 -0
  8. chromaquant/formula/base_formulas.py +168 -0
  9. chromaquant/formula/formula.py +507 -0
  10. chromaquant/import_local_packages.py +55 -0
  11. chromaquant/logging_and_handling.py +76 -0
  12. chromaquant/match/__init__.py +13 -0
  13. chromaquant/match/match.py +184 -0
  14. chromaquant/match/match_config.py +296 -0
  15. chromaquant/match/match_tools.py +154 -0
  16. chromaquant/{Quant → results}/__init__.py +2 -2
  17. chromaquant/results/reporting_tools.py +190 -0
  18. chromaquant/results/results.py +250 -0
  19. chromaquant/utils/__init__.py +14 -0
  20. chromaquant/utils/categories.py +127 -0
  21. chromaquant/utils/chemical_formulas.py +104 -0
  22. chromaquant/utils/dataframe_processing.py +222 -0
  23. chromaquant/utils/file_tools.py +100 -0
  24. chromaquant/utils/formula_tools.py +119 -0
  25. chromaquant-0.5.0.dist-info/METADATA +61 -0
  26. chromaquant-0.5.0.dist-info/RECORD +29 -0
  27. {chromaquant-0.4.0.dist-info → chromaquant-0.5.0.dist-info}/WHEEL +1 -1
  28. {chromaquant-0.4.0.dist-info → chromaquant-0.5.0.dist-info}/licenses/LICENSE.txt +1 -1
  29. chromaquant-0.5.0.dist-info/licenses/LICENSES_bundled.txt +251 -0
  30. chromaquant/Handle/__init__.py +0 -13
  31. chromaquant/Handle/fileChecks.py +0 -172
  32. chromaquant/Handle/handleDirectories.py +0 -89
  33. chromaquant/Hydro/__init__.py +0 -12
  34. chromaquant/Hydro/hydroMain.py +0 -496
  35. chromaquant/Manual/HydroUI.py +0 -418
  36. chromaquant/Manual/QuantUPP.py +0 -373
  37. chromaquant/Manual/Quantification.py +0 -1305
  38. chromaquant/Manual/__init__.py +0 -10
  39. chromaquant/Manual/duplicateMatch.py +0 -211
  40. chromaquant/Manual/fpm_match.py +0 -798
  41. chromaquant/Manual/label-type.py +0 -179
  42. chromaquant/Match/AutoFpmMatch.py +0 -1133
  43. chromaquant/Match/MatchSub/__init__.py +0 -13
  44. chromaquant/Match/MatchSub/matchTools.py +0 -282
  45. chromaquant/Match/MatchSub/peakTools.py +0 -259
  46. chromaquant/Match/__init__.py +0 -13
  47. chromaquant/Match/matchMain.py +0 -233
  48. chromaquant/Quant/AutoQuantification.py +0 -1329
  49. chromaquant/Quant/QuantSub/__init__.py +0 -15
  50. chromaquant/Quant/QuantSub/gasFID.py +0 -241
  51. chromaquant/Quant/QuantSub/gasTCD.py +0 -425
  52. chromaquant/Quant/QuantSub/liquidFID.py +0 -310
  53. chromaquant/Quant/QuantSub/parseTools.py +0 -162
  54. chromaquant/Quant/quantMain.py +0 -417
  55. chromaquant/UAPP/__init__.py +0 -12
  56. chromaquant/UAPP/uappMain.py +0 -427
  57. chromaquant/__main__.py +0 -526
  58. chromaquant/oldui.py +0 -492
  59. chromaquant/properties.json +0 -4
  60. chromaquant-0.4.0.dist-info/METADATA +0 -189
  61. chromaquant-0.4.0.dist-info/RECORD +0 -38
  62. chromaquant-0.4.0.dist-info/entry_points.txt +0 -2
  63. chromaquant-0.4.0.dist-info/licenses/LICENSES_bundled.txt +0 -1035
@@ -1,15 +0,0 @@
1
- #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
-
4
- """
5
- ChromaQuant.Match.MatchSub package initialization
6
-
7
- Julia Hancock
8
- Created 10-19-2024
9
-
10
- """
11
-
12
- from .parseTools import *
13
- from .liquidFID import *
14
- from .gasFID import *
15
- from .gasTCD import *
@@ -1,241 +0,0 @@
1
- #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
- """
4
- COPYRIGHT STATEMENT:
5
-
6
- ChromaQuant – A quantification software for complex gas chromatographic data
7
-
8
- Copyright (c) 2024, by Julia Hancock
9
- Affiliation: Dr. Julie Elaine Rorrer
10
- URL: https://www.rorrerlab.com/
11
-
12
- License: BSD 3-Clause License
13
-
14
- ---
15
-
16
- SUBPACKAGE FOR PERFORMING GAS FID QUANTIFICATION STEPS
17
-
18
- Julia Hancock
19
- Started 12-29-2024
20
-
21
- """
22
- """ PACKAGES """
23
- import pandas as pd
24
- import numpy as np
25
- from chemformula import ChemFormula
26
-
27
- #Function for quantifying gas FID data w/ external standard
28
- def gasFID_ES(BreakdownDF,DBRF,Label_info,gasBag_cond,total_volume,cutoff=4):
29
- """
30
- Function quantifies gas FID data and returns a breakdown dataframe
31
-
32
- Parameters
33
- ----------
34
- BreakdownDF : DataFrame
35
- Dataframe containing columns associated with matched FID and MS peak data
36
- DBRF : Dataframe
37
- Dataframe containing nested dataframes with associated chemical lumps,
38
- likely imported from an excel sheet where each sheet is specific to
39
- a given chemical lump. The top-level keys must be associated with the
40
- predefined chemical lumps given in 'LABELS' section above
41
- gasBag_cond : List
42
- List containing gas bag temperature [0] and gas bag pressure [1]
43
- Label_info : List
44
- List of dictionaries containing chemical lump and compound type abbreviations
45
- total_volume : Float
46
- Float describing the total amount of gas estimated by the external standard volume percent, mL
47
- cutoff : Integer, optional
48
- Integer representing the maximum cutoff carbon number that can be
49
- quantified using FID.The default is 4.
50
-
51
- Returns
52
- -------
53
- BreakdownDF : DataFrame
54
- Dataframe containing columns associated with matched FID and MS peak data
55
-
56
- """
57
- #Function for assigning response factors to compounds
58
- def assignRF(BreakdownDF,DBRF):
59
-
60
- #Get a dictionary of average response factors by carbon number
61
- avgRF = {}
62
- #Loop through every carbon number up to the max in DBRF
63
- for i in range(1,DBRF['Carbon Number'].max()+1):
64
- #Get a slice of all rows in DBRF with a given carbon number
65
- slicer = DBRF.loc[DBRF['Carbon Number']==i]
66
- #Average the response factor entries in this slice, appending the result to the average RF dictionary
67
- avgRF['{0}'.format(i)] = slicer['RF'].mean()
68
-
69
- #Loop through every row in the FIDpMS dataframe
70
- for i, row in BreakdownDF.iterrows():
71
- #Check that the formula is not nan
72
- if not pd.isna(row['Formula']):
73
- #Obtain a dictionary containing key:value pairs as element:count using the formula string for the ith row
74
- chemFormDict = ChemFormula(row['Formula']).element
75
- #Use the carbon entry from the above dictionary to assign a carbon number to the ith row
76
- BreakdownDF.at[i,'Carbon Number'] = chemFormDict['C']
77
-
78
- #If the row's compound name exists in the RF list explicitly, assign the row to the appropriate RF
79
- if row['Compound Name'] in DBRF['Compound Name'].values:
80
- BreakdownDF.at[i,'RF (Area/vol.%)'] = DBRF.loc[DBRF['Compound Name']==row['Compound Name'],'RF'].iloc[0]
81
- #Assign response factor source
82
- BreakdownDF.at[i,'RF Source'] = 'Direct RF assignment based on compound name'
83
- #Otherwise, assign response factor based on average carbon number RF
84
- else:
85
- BreakdownDF.at[i,'RF (Area/vol.%)'] = avgRF['{0}'.format(int(BreakdownDF.at[i,'Carbon Number']))]
86
- #Assign response factor source
87
- BreakdownDF.at[i,'RF Source'] = 'RF assignment based on average response factor for DBRF carbon number entries'
88
- #Otherwise if the row's formula is nan, pass
89
- else:
90
- pass
91
-
92
-
93
- return BreakdownDF
94
-
95
- #Function for quantifying compounds using ideal gas law
96
- def gasQuant(BreakdownDF,DBRF,total_volume,cutoff):
97
-
98
- #Remove rows in BreakdownDF with a carbon number at or below cutoff
99
- BreakdownDF = BreakdownDF.loc[BreakdownDF['Carbon Number'] > cutoff].copy()
100
-
101
- #Get gas bag conditions
102
- temp = gasBag_cond[0] #temperature of gas bag, C
103
- pressure = gasBag_cond[1] #sample pressure in gas bag, psi
104
-
105
- #Convert gas bag conditions to new units
106
- temp = temp + 273.15 #gas bag temperature, K
107
- pressure = pressure / 14.504*100000 #gas bag pressure, Pa
108
- total_volume /= 10**6 #gas bag volume, m^3
109
- #Define ideal gas constant, m^3*Pa/K*mol
110
- R = 8.314
111
-
112
- #Loop through every row in BreakdownDF
113
- for i, row in BreakdownDF.iterrows():
114
-
115
- #Add molecular weight using ChemFormula
116
- BreakdownDF.at[i,'MW (g/mol)'] = ChemFormula(row['Formula']).formula_weight
117
-
118
- #Get volume percent using response factor
119
- BreakdownDF.at[i,'Vol.%'] = row['FID Area']/row['RF (Area/vol.%)']
120
-
121
- #Get moles using ideal gas law (PV=nRT)
122
- BreakdownDF.at[i,'Moles'] = BreakdownDF.at[i,'Vol.%']/100*total_volume*pressure/(temp*R)
123
-
124
- #Get mass (mg) using moles and molar mass
125
- BreakdownDF.at[i,'Mass (mg)'] = BreakdownDF.at[i,'Moles'] * BreakdownDF.at[i,'MW (g/mol)'] * 1000
126
-
127
- return BreakdownDF
128
-
129
- #Function for further breaking down product distribution
130
- def moreBreakdown(BreakdownDF,CT_dict):
131
- """
132
- This function prepares further breakdown dictionaries for use in exporting to Excel
133
-
134
- Parameters
135
- ----------
136
- BreakdownDF : DataFrame
137
- Dataframe containing columns associated with matched FID and MS peak data.
138
- CT_dict : Dict
139
- Dictionary of all compound type abbreviations in use and their associated expansions
140
-
141
- Returns
142
- -------
143
- BreakdownDF : DataFrame
144
- Dataframe containing columns associated with matched FID and MS peak data.
145
-
146
- """
147
-
148
- #Get the total mass of product from the breakdown dataframe
149
- m_total = np.nansum(BreakdownDF['Mass (mg)'])
150
-
151
- #Iterate through every species in the breakdown dataframe and add entries in two new columns: Compound Type and Carbon Number
152
- for i, row in BreakdownDF.iterrows():
153
- #If there exists a formula..
154
- try:
155
- #Set breakdown compound type according to the abbreviation already in the breakdown dataframe
156
- BreakdownDF.at[i,'Compound Type'] = CT_dict[BreakdownDF.at[i,'Compound Type Abbreviation']]
157
- #Obtain a dictionary containing key:value pairs as element:count using the formula string for the ith row
158
- chemFormDict = ChemFormula(row['Formula']).element
159
- #Use the carbon entry from the above dictionary to assign a carbon number to the ith row
160
- BreakdownDF.at[i,'Carbon Number'] = chemFormDict['C']
161
- #Otherwise, pass
162
- except:
163
- pass
164
-
165
- #Get maximum carbon number in breakdown dataframe
166
- CN_max = int(BreakdownDF['Carbon Number'].max())
167
-
168
- #Create a dataframe for saving quantitative results organized by compound type
169
- CT_DF = pd.DataFrame({'Compound Type':['Aromatics','Linear Alkanes','Branched Alkanes',
170
- 'Cycloalkanes','Alkenes/Alkynes','Other'],
171
- 'Mass (mg)':np.empty(6),
172
- 'Mass fraction':np.empty(6)})
173
-
174
- #Create a dataframe for saving quantitative results organized by carbon number
175
- CN_DF = pd.DataFrame({'Carbon Number':range(1,CN_max+1,1),
176
- 'Mass (mg)':np.empty(CN_max)})
177
-
178
- #Create a dataframe for saving quantitative results organized by both compound type and carbon number
179
- CTCN_DF = pd.DataFrame({'Aromatics': pd.Series(np.empty(CN_max),index=range(CN_max)),
180
- 'Linear Alkanes': pd.Series(np.empty(CN_max),index=range(CN_max)),
181
- 'Branched Alkanes':pd.Series(np.empty(CN_max),index=range(CN_max)),
182
- 'Cycloalkanes':pd.Series(np.empty(CN_max),index=range(CN_max)),
183
- 'Alkenes/Alkynes':pd.Series(np.empty(CN_max),index=range(CN_max)),
184
- 'Other':pd.Series(np.empty(CN_max),index=range(CN_max))})
185
-
186
- #Iterate through every compound type in the compound type dataframe, summing the total respective masses from the breakdown dataframe
187
- for i, row in CT_DF.iterrows():
188
-
189
- #Define a temporary dataframe which contains all rows matching the ith compound type
190
- tempDF = BreakdownDF.loc[BreakdownDF['Compound Type'] == row['Compound Type']]
191
- #Assign the ith compound type's mass as the sum of the temporary dataframe's m_i column, treating nan as zero
192
- CT_DF.at[i,'Mass (mg)'] = np.nansum(tempDF['Mass (mg)'])
193
- #Calculate and assign the ith compound type's mass fraction usingthe total mass from earlier
194
- CT_DF.at[i,'Mass fraction'] = CT_DF.at[i,'Mass (mg)']/m_total
195
-
196
- #Iterate through every carbon number in the carbon number dataframe, summing the total respective masses from the breakdown dataframe
197
- for i, row in CN_DF.iterrows():
198
-
199
- #Define a temporary dataframe which contains all rows matching the ith carbon number
200
- tempDF = BreakdownDF.loc[BreakdownDF['Carbon Number'] == row['Carbon Number']]
201
- #Assign the ith carbon number's mass as the sum of the temporary dataframe's m_i column, treating nan as zero
202
- CN_DF.at[i,'Mass (mg)'] = np.nansum(tempDF['Mass (mg)'])
203
-
204
- #Iterate through the entire dataframe, getting masses for every compound type - carbon number pair
205
- for i, row in CTCN_DF.iterrows():
206
-
207
- #For every entry in row
208
- for j in row.index:
209
-
210
- #Define a temporary dataframe which contains all rows matching the ith carbon number and compound type
211
- tempDF = BreakdownDF.loc[(BreakdownDF['Carbon Number'] == i+1) & (BreakdownDF['Compound Type'] == j)]
212
- #Assign the ith carbon number/jth compound type's mass as the sum of the temporary dataframe's m_i column, treating nan as zero
213
- CTCN_DF.loc[i,j] = np.nansum(tempDF['Mass (mg)'])
214
-
215
-
216
- #Get total masses from CT, CN, and CTCN dataframes
217
- CT_mass = np.nansum(CT_DF['Mass (mg)'])
218
- CN_mass = np.nansum(CN_DF['Mass (mg)'])
219
- CTCN_mass = np.nansum(CTCN_DF)
220
-
221
- #Create total mass dataframe
222
- mass_DF = pd.DataFrame({'Total mass source':['Overall breakdown','Compound Type Breakdown','Carbon Number Breakdown','Compound Type + Carbon Number Breakdown'],'Mass (mg)':[m_total,CT_mass,CN_mass,CTCN_mass]})
223
-
224
- return BreakdownDF, CT_DF, CN_DF, CTCN_DF, mass_DF
225
-
226
- #Unpack compound type and carbon number dictionaries from list
227
- CL_Dict, CT_Dict = Label_info
228
-
229
- #Filter dataframe to remove compounds that do not contain carbon
230
- BreakdownDF = BreakdownDF.drop(BreakdownDF[[not i for i in BreakdownDF['Formula'].str.contains('C')]].index)
231
- #Reset the dataframe index
232
- BreakdownDF.reset_index()
233
-
234
- #Run response factor assignment function
235
- BreakdownDF = assignRF(BreakdownDF, DBRF)
236
- #Run gas quantification function
237
- BreakdownDF = gasQuant(BreakdownDF,DBRF,total_volume,cutoff)
238
- #Run further breakdown function
239
- BreakdownDF, CT_DF, CN_DF, CTCN_DF, mass_DF = moreBreakdown(BreakdownDF, CT_Dict)
240
-
241
- return BreakdownDF, CT_DF, CN_DF, CTCN_DF, mass_DF
@@ -1,425 +0,0 @@
1
- #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
- """
4
- COPYRIGHT STATEMENT:
5
-
6
- ChromaQuant – A quantification software for complex gas chromatographic data
7
-
8
- Copyright (c) 2024, by Julia Hancock
9
- Affiliation: Dr. Julie Elaine Rorrer
10
- URL: https://www.rorrerlab.com/
11
-
12
- License: BSD 3-Clause License
13
-
14
- ---
15
-
16
- SUBPACKAGE FOR PERFORMING GAS TCD QUANTIFICATION STEPS
17
-
18
- Julia Hancock
19
- Started 12-29-2024
20
-
21
- """
22
- """ PACKAGES """
23
- from chemformula import ChemFormula
24
-
25
- #Function for quantifying gas TCD data w/ volume estimation method, no pressure adjustment
26
- def gasTCD_VE(BreakdownDF,DBRF,gasBag_cond,peak_error):
27
-
28
- #Unpack gas bag conditions
29
- temp = gasBag_cond[0] #temperature of gas bag, C
30
- pressure = gasBag_cond[1] #sample pressure in gas bag, psi
31
- co2 = gasBag_cond[2] #CO2 volume, mL
32
-
33
- #Initialize compound name column in BreakdownDF
34
- BreakdownDF['Compound Name'] = 'None'
35
-
36
- #Function to find if CO2 peak exists
37
- def getCO2(BreakdownDF,DBRF,TCD_cond,peak_error):
38
-
39
- #Unpack TCD conditions
40
- co2 = TCD_cond[0]
41
- pressure = TCD_cond[1]
42
- temp = TCD_cond[2]
43
- R = TCD_cond[3]
44
-
45
- #Find the CO2 peak row in DBRF
46
- CO2_row = DBRF.loc[DBRF['Compound Name'] == "Carbon Dioxide"].iloc[0]
47
-
48
- #Get the retention time
49
- CO2_RT = CO2_row['RT (min)']
50
-
51
- #Get the minimum and maximum of the RT range using the peak error
52
- CO2_RTmin = CO2_RT - peak_error
53
- CO2_RTmax = CO2_RT + peak_error
54
-
55
- #Define boolean describing whether or not CO2 match has been found
56
- CO2_bool = False
57
- #Define volume estimate
58
- volume = 0
59
-
60
- #Iterate through every row in BreakdownDF
61
- for i, row in BreakdownDF.iterrows():
62
-
63
- #If the TCD retention time is within range of the CO2 entry...
64
- if CO2_RTmin <= row['RT'] <= CO2_RTmax:
65
-
66
- #Add the compound name to the breakdown dataframe
67
- BreakdownDF.at[i,'Compound Name'] = 'Carbon Dioxide'
68
-
69
- #Add the other relevant information to the breakdown dataframe
70
- BreakdownDF.at[i,'Formula'] = 'CO2'
71
- BreakdownDF.at[i,'RF (Area/vol.%)'] = CO2_row['RF']
72
- BreakdownDF.at[i,'MW (g/mol)'] = ChemFormula('CO2').formula_weight
73
-
74
- #Get volume percent using response factor
75
- volpercent = row['Area']/CO2_row['RF']
76
- BreakdownDF.at[i,'Vol.%'] = volpercent
77
-
78
- #Calculate total volume using volume percent
79
- volume = co2 * 100 / volpercent #total volume, m^3
80
-
81
- #Assign CO2 volume
82
- BreakdownDF.at[i,'Volume (m^3)'] = co2
83
-
84
- #Get moles using ideal gas law (PV=nRT)
85
- BreakdownDF.at[i,'Moles (mol)'] = co2*pressure/(temp*R)
86
-
87
- #Get mass (mg) using moles and molar mass
88
- BreakdownDF.at[i,'Mass (mg)'] = BreakdownDF.at[i,'Moles (mol)'] * BreakdownDF.at[i,'MW (g/mol)'] * 1000
89
-
90
- #Set CO2_bool to True
91
- CO2_bool = True
92
-
93
- break
94
-
95
- #Otherwise, pass
96
- else:
97
- pass
98
-
99
- return CO2_bool, volume, BreakdownDF
100
-
101
- #Add min and max peak assignment values to DBRF
102
- for i, row in DBRF.iterrows():
103
- DBRF.at[i,'RT Max'] = DBRF.at[i,'RT (min)'] + peak_error
104
- DBRF.at[i,'RT Min'] = DBRF.at[i,'RT (min)'] - peak_error
105
-
106
- #Convert sinfo variables to new units
107
- co2 = co2 / 10**6 #volume injected CO2, m^3
108
- temp = temp + 273.15 #reactor temperature, K
109
- pressure = pressure / 14.504*100000 #reactor pressure, Pa
110
-
111
- #Define ideal gas constant, m^3*Pa/K*mol
112
- R = 8.314
113
-
114
- #Define variable to total volume (m^3)
115
- V_TC = 0
116
-
117
- #Define list of conditions
118
- TCD_cond = [co2,pressure,temp,R]
119
-
120
- #Check if there is a peak in the BreakdownDF that can be assigned to CO2
121
- CO2_bool, V_TC, BreakdownDF = getCO2(BreakdownDF,DBRF,TCD_cond,peak_error)
122
-
123
- if CO2_bool:
124
- #Iterate through every row in BreakdownDF
125
- for i, row in BreakdownDF.iterrows():
126
-
127
- #Iterate through every row in DBRF
128
- for i2, row2 in DBRF.iterrows():
129
-
130
- #If the TCD retention time is within the range for a given DBRF entry...
131
- if row2['RT Min'] <= row['RT'] <= row2['RT Max']:
132
-
133
- #Add the compound name to the breakdown dataframe
134
- BreakdownDF.at[i,'Compound Name'] = row2['Compound Name']
135
-
136
- #Add the other relevant information to the breakdown dataframe
137
- BreakdownDF.at[i,'Formula'] = row2['Formula']
138
- BreakdownDF.at[i,'RF (Area/vol.%)'] = row2['RF']
139
- BreakdownDF.at[i,'MW (g/mol)'] = ChemFormula(row2['Formula']).formula_weight
140
-
141
- #Get volume percent using response factor
142
- volpercent = row['Area']/row2['RF']
143
- BreakdownDF.at[i,'Vol.%'] = volpercent
144
-
145
- #Get volume using volume percent
146
- vol = V_TC*volpercent/100
147
- BreakdownDF.at[i,'Volume (m^3)'] = vol
148
-
149
- #Get moles using ideal gas law (PV=nRT)
150
- BreakdownDF.at[i,'Moles (mol)'] = vol*pressure/(temp*R)
151
-
152
- #Get mass (mg) using moles and molar mass
153
- BreakdownDF.at[i,'Mass (mg)'] = BreakdownDF.at[i,'Moles (mol)'] * BreakdownDF.at[i,'MW (g/mol)'] * 1000
154
-
155
- #Otherwise, pass
156
- else:
157
- pass
158
- #Otherwise, pass
159
- else:
160
- pass
161
-
162
- #Convert total volume to mL
163
- V_TC *= 10**6
164
-
165
- return BreakdownDF, V_TC
166
-
167
- #Function for quantifying gas TCD data w/ scale factor method
168
- def gasTCD_SF(BreakdownDF,DBRF,gasBag_cond,reactor_cond,peak_error):
169
-
170
- #Initialize compound name column in BreakdownDF
171
- BreakdownDF['Compound Name'] = 'None'
172
-
173
- #Function to determine total volume using ideal gas law
174
- def volumeIGL(V_C,reactor_cond):
175
-
176
- #Unpack reactor conditions
177
- P_f = reactor_cond[0] #reactor quench pressure, psig
178
- V_R = reactor_cond[1] #reactor internal volume, mL
179
- P_0 = reactor_cond[2] #atmospheric pressure, psi
180
-
181
- #Estimate total volume of gas bag, mL
182
- V_T = V_R * (P_f + P_0) / P_0
183
-
184
- #Estimate total volume of gas bag plus volume CO2, mL
185
- V_TC = V_T + V_C
186
-
187
- return V_T, V_TC
188
-
189
- # Function to estimate scale factor from CO2
190
- def getScaleFactor(BreakdownDF,DBRF,V_C,V_TC):
191
-
192
- #Find the CO2 peak row in DBRF
193
- CO2_row = DBRF.loc[DBRF['Compound Name'] == "Carbon Dioxide"].iloc[0]
194
-
195
- #Get the retention time
196
- CO2_RT = CO2_row['RT (min)']
197
-
198
- #Get the minimum and maximum of the RT range using the peak error
199
- CO2_RTmin = CO2_RT - peak_error
200
- CO2_RTmax = CO2_RT + peak_error
201
-
202
- #Define boolean describing whether or not CO2 match has been found
203
- CO2_bool = False
204
-
205
- #Iterate through every row in BreakdownDF
206
- for i, row in BreakdownDF.iterrows():
207
-
208
- #If the TCD retention time is within range of the CO2 entry...
209
- if CO2_RTmin <= row['RT'] <= CO2_RTmax:
210
-
211
- #Get estimated volume fraction of CO2
212
- psiCO2_e = row['Area'] / (100 * CO2_row['RF'])
213
-
214
- #Get actual volume fraction of CO2
215
- psiCO2_a = V_C / V_TC
216
-
217
- #Define scale factor as ratio of actual volume fraction to estimated volume fraction
218
- SF = psiCO2_a / psiCO2_e
219
-
220
- #Set CO2_bool to True
221
- CO2_bool = True
222
-
223
- break
224
-
225
- #Otherwise, pass
226
- else:
227
- pass
228
-
229
- #Raise error if no CO2 peak found
230
- if CO2_bool == False:
231
- raise Exception("[gasTCD][ERROR] No CO2 peak found in TCD")
232
-
233
- else:
234
- pass
235
-
236
- return SF
237
-
238
- #Function to calculate amounts of each species using the scale factor
239
- def quantTCD(BreakdownDF,DBRF,gasBag_cond,reactor_cond):
240
-
241
- # Unpack gas bag conditions
242
- GB_temp = gasBag_cond[0] # Temperature of gas bag, C
243
- GB_pressure = gasBag_cond[1] # Sample pressure in gas bag, psig
244
- V_C = gasBag_cond[2] # CO2 volume, mL
245
-
246
- # Get total and total+CO2 gas bag volumes
247
- V_T, V_TC = volumeIGL(V_C,reactor_cond)
248
-
249
- # Define ideal gas constant, m^3*Pa/K*mol
250
- R = 8.314
251
-
252
- #Define conversion factor, Pa * m^3 * psi^-1 * mL^-1
253
- C = 0.00689476
254
-
255
- #Get scale factor
256
- SF = getScaleFactor(BreakdownDF,DBRF,V_C,V_TC)
257
-
258
- #Add min and max peak assignment values to DBRF
259
- for i, row in DBRF.iterrows():
260
- DBRF.at[i,'RT Max'] = DBRF.at[i,'RT (min)'] + peak_error
261
- DBRF.at[i,'RT Min'] = DBRF.at[i,'RT (min)'] - peak_error
262
-
263
- #Iterate through every row in BreakdownDF
264
- for i, row in BreakdownDF.iterrows():
265
-
266
- #Iterate through every row in DBRF
267
- for i2, row2 in DBRF.iterrows():
268
-
269
- #If the TCD retention time is within the range for a given DBRF entry...
270
- if row2['RT Min'] <= row['RT'] <= row2['RT Max']:
271
-
272
- #Add the compound name to the breakdown dataframe
273
- BreakdownDF.at[i,'Compound Name'] = row2['Compound Name']
274
-
275
- #Add the other relevant information to the breakdown dataframe
276
- BreakdownDF.at[i,'Formula'] = row2['Formula']
277
- BreakdownDF.at[i,'RF (Area/vol.%)'] = row2['RF']
278
- BreakdownDF.at[i,'MW (g/mol)'] = ChemFormula(row2['Formula']).formula_weight
279
-
280
- #Get estimated volume percent using response factor
281
- volpercent_e = row['Area']/row2['RF']
282
- BreakdownDF.at[i,'Est. Vol.%'] = volpercent_e
283
-
284
- #Get adjusted volume percent using scale factor
285
- volpercent_a = volpercent_e * SF
286
- BreakdownDF.at[i,'Adj. Vol.%'] = volpercent_a
287
-
288
- #Get moles using ideal gas law (PV=nRT)
289
- BreakdownDF.at[i,'Moles (mol)'] = C * (GB_pressure * volpercent_a / 100 * V_TC)/(R * (GB_temp + 273.15))
290
-
291
- #Get mass (mg) using moles and molar mass
292
- BreakdownDF.at[i,'Mass (mg)'] = BreakdownDF.at[i,'Moles (mol)'] * BreakdownDF.at[i,'MW (g/mol)'] * 1000
293
-
294
- #Otherwise, pass
295
- else:
296
- pass
297
-
298
- return BreakdownDF, V_TC, SF
299
-
300
- BreakdownDF, V_TC, SF = quantTCD(BreakdownDF,DBRF,gasBag_cond,reactor_cond)
301
-
302
- return BreakdownDF, V_TC, SF
303
-
304
- #Function for quantifying gas TCD data w/ internal standard method
305
- def gasTCD_IS(BreakdownDF,DBRF,gasBag_cond,reactor_cond,peak_error):
306
-
307
- #Initialize compound name column in BreakdownDF
308
- BreakdownDF['Compound Name'] = 'None'
309
-
310
- #Define molar mass of CO2, g/mol
311
- Mc = 44.009
312
-
313
- # Function to estimate mass of CO2 from provided conditions and get area of CO2
314
- def massCO2(BreakdownDF,DBRF,R,C,V_C,P_0,GB_temp):
315
-
316
- #Find the CO2 peak row in DBRF
317
- CO2_row = DBRF.loc[DBRF['Compound Name'] == "Carbon Dioxide"].iloc[0]
318
-
319
- #Get the retention time
320
- CO2_RT = CO2_row['RT (min)']
321
-
322
- #Get the minimum and maximum of the RT range using the peak error
323
- CO2_RTmin = CO2_RT - peak_error
324
- CO2_RTmax = CO2_RT + peak_error
325
-
326
- #Define boolean describing whether or not CO2 match has been found
327
- CO2_bool = False
328
-
329
- #Iterate through every row in BreakdownDF
330
- for i, row in BreakdownDF.iterrows():
331
-
332
- #If the TCD retention time is within range of the CO2 entry...
333
- if CO2_RTmin <= row['RT'] <= CO2_RTmax:
334
-
335
- #Get mass of CO2, mg
336
- mc = C * Mc * (P_0 * V_C) / (R * (GB_temp + 273.15)) * 1000
337
-
338
- #Get area of CO2
339
- Ac = row['Area']
340
-
341
- #Set CO2_bool to True
342
- CO2_bool = True
343
-
344
- break
345
-
346
- #Otherwise, pass
347
- else:
348
- pass
349
-
350
- #Raise error if no CO2 peak found
351
- if CO2_bool == False:
352
- raise Exception("[gasTCD][ERROR] No CO2 peak found in TCD")
353
-
354
- else:
355
- pass
356
-
357
- return mc, Ac
358
-
359
- #Function to calculate amounts of each species using the scale factor
360
- def quantTCD(BreakdownDF,DBRF,gasBag_cond,reactor_cond):
361
-
362
- # Unpack gas bag conditions
363
- GB_temp = gasBag_cond[0] # Temperature of gas bag, C
364
- GB_pressure = gasBag_cond[1] # Sample pressure in gas bag, psig
365
- V_C = gasBag_cond[2] # CO2 volume, mL
366
-
367
- #Unpack reactor conditions
368
- P_f = reactor_cond[0] #reactor quench pressure, psig
369
- V_R = reactor_cond[1] #reactor internal volume, mL
370
- P_0 = reactor_cond[2] #atmospheric pressure, psi
371
-
372
- # Define ideal gas constant, m^3*Pa/K*mol
373
- R = 8.314
374
-
375
- #Define conversion factor, Pa * m^3 * psi^-1 * mL^-1
376
- C = 0.00689476
377
-
378
- #Get mass of CO2
379
- mc, Ac = massCO2(BreakdownDF,DBRF,R,C,V_C,P_0,GB_temp)
380
-
381
- #Get total volume plus CO2
382
- V_T = V_R * (P_f + P_0) / P_0
383
- V_TC = V_T + V_C
384
- print(V_TC)
385
- #Add min and max peak assignment values to DBRF
386
- for i, row in DBRF.iterrows():
387
- DBRF.at[i,'RT Max'] = DBRF.at[i,'RT (min)'] + peak_error
388
- DBRF.at[i,'RT Min'] = DBRF.at[i,'RT (min)'] - peak_error
389
-
390
- #Iterate through every row in BreakdownDF
391
- for i, row in BreakdownDF.iterrows():
392
-
393
- #Iterate through every row in DBRF
394
- for i2, row2 in DBRF.iterrows():
395
-
396
- #If the TCD retention time is within the range for a given DBRF entry...
397
- if row2['RT Min'] <= row['RT'] <= row2['RT Max']:
398
-
399
- #Add the compound name to the breakdown dataframe
400
- BreakdownDF.at[i,'Compound Name'] = row2['Compound Name']
401
-
402
- #Add the other relevant information to the breakdown dataframe
403
- BreakdownDF.at[i,'Formula'] = row2['Formula']
404
- BreakdownDF.at[i,'RF'] = row2['RF']
405
- BreakdownDF.at[i,'MW (g/mol)'] = ChemFormula(row2['Formula']).formula_weight
406
-
407
- #If the peak is CO2...
408
- if row['Compound Name'] == "Carbon Dioxide":
409
- #Set mass to mc
410
- BreakdownDF.at[i,'Mass(mg)'] = mc
411
-
412
- #Otherwise...
413
- else:
414
- #Get mass (mg) using mass of carbon dioxide and response factor
415
- BreakdownDF.at[i,'Mass (mg)'] = (mc * (BreakdownDF.at[i,'Area'] / Ac)) / BreakdownDF.at[i,'RF']
416
-
417
- #Otherwise, pass
418
- else:
419
- pass
420
-
421
- return BreakdownDF, V_TC
422
-
423
- BreakdownDF, V_TC = quantTCD(BreakdownDF,DBRF,gasBag_cond,reactor_cond)
424
-
425
- return BreakdownDF, V_TC