Module DEWPython Documentation
Expand source code
global Tr, bigQ, Chi, Pr, E_PrTr, bigR, Psi, Theta, Upsilon, Conversion, mineralDictionary
# Defining global constants analagous to DEW 2019
bigQ = 5.903E-07
'''Big Q is the 5.903E-07, and has units of bar^-1 '''
Chi = -3.090E-07
'''X is the constant -3.090E-07 and has units of K^-2'''
T_r = 298.15
'''The standard state temperature 298.15 with units K'''
Pr = 1
'''The standard state pressure of 1 bar'''
E_PrTr = 78.47
'''Epsilon_{P_rT_r} is a unitless constant with value of 78.47'''
bigR = 1.9858775
'''The gas constant with value 1.9858775 cal mol^-1 k^-1'''
Psy = 2600
'''The value of this constant is 2600 bar'''
Theta = 228
'''The value of this temperature is 228 Kelvin'''
Upsilon = -5.79865E-05
'''The value of this constant is -5.79865E-05 K^-1'''
Conversion = 41.8393
'''A conversion factor present in DEW publications'''
# Search function - can take any length of string
def search(string):
'''A function to searh for species within DEWython'''
for item in nameLst:
if str.lower(string) in str.lower(item):
print(item)
for item in GasLst:
if str.lower(string) in str.lower(item):
print(item)
for key in mineralDictionary:
if str.lower(string) in str.lower(key):
print(key)
# # An Object Class that Can Calculate and Return Parameters for Different Options of the Deep Earth Water Model
class DEW(object):
def __init__(self):
# User Option Parameters
self.ptInput = 'Psat'
'''The temperature and pressure input, options are Regular, Psat, or custom. Default is regular'''
self.RhoOfWater = 'Z&D 2005'
'''The density of water equation input, can be Zheng and Duan 2005, Zheng and Duan 2009, or custom. Default is Z&D 2005'''
self.forceCustom = False
'''The option to force custom Rho for P< 1 kb. Default is False'''
self.dielectricEq = 'Supcrt'
'''The dielectric equation input. The default is Sverjensky.'''
self.ForceSupcrt = True
'''The option to force supcrt for P < 5 kb. Default is set to true'''
self.WaterFreeEq = 'D&H 1978'
'''The option for the Water free energy equation. Options are D&H 1978, integral, and custom
Default is Delaney and Hegelson 1978.'''
self.DisplayVolOpt = True
'''The option to display volume, default set to true'''
self.PsatDisplayVol = True
'''The option to display volume under Psat conditions. Default is set to true.'''
self.DisplayVol = True
'''Another display volume option. Default to true.'''
self.equation = 1
'''A variable that stores the number of the density of water equation. Needs to be renamed'''
self.diaEq = 1
'''A variable that stores the number of dielectric constant equation.'''
self.psat = True
'''A variable that stores the Psat option defined by input'''
self.waterDensity = 1
'''A variable that stores the number of the density of water equation.'''
# Input Arrays
self.aqueousInputs = []
'''The array of aqueous inputs and multipliers defined by a user'''
self.mineralInputs = []
'''The array of mineral inputs and multipliers defined by a user'''
self.gasInputs = []
'''The array of gas inputs and multipliers defined by a user'''
self.waterInputs = []
'''An array that defines if water is used in the input and hOw mUcH wAtEr?'''
# Input Matrices
self.inGasMat = []
'''A matrix that stores in gasseous inputs with their properties from the dicitonary inputs'''
self.inAqMat = []
'''A matrix that stores in aqueous inputs with their properties from the dicitonary inputs'''
# Output Arrays
self.aqueousOutputs = []
'''The array of aqueous outputs and multipliers defined by a user'''
self.mineralOutputs = []
'''The array of mineral outputs and multipliers defined by a user'''
self.gasOutputs = []
'''The array of gas outputs and multipliers defined by a user'''
self.waterOutputs = []
'''An array that defines if water is used in the outputand hOw mUcH wAtEr?'''
# Output Matrices
self.outGasMat = []
'''A matrix that stores in gasseous outputs with their properties from the dicitonary inputs'''
self.outAqMat = []
'''A matrix that stores in aqueous outputs with their properties from the dicitonary inputs'''
# Arrays used for Calculations
self.tempUsed = []
'''An array set by the set_TPRho method that contains all the temperatures used for calculation in celsius'''
self.pressureUsed = []
'''An array set by the set_TPRho method that contains all the pressures used for calculation'''
self.tKelvin = []
'''An array set by the set_TPRho method that contains all the temperatures used for calculation in Kelvin'''
self.RhoWatArr = []
'''An array set by the set_TPRho method that contains calculated water densities at the temperatures and pressures used
'''
self.DiaArr = []
'''An array set by the set_TPRho method that contains calculated dielectric constants at temp/pressure used'''
self.QArr = []
'''An array set by the set_TPRho method that contains calculated Q constants at temp/pressure used'''
self.GibbsH2O = []
'''A collection of the gibbs of water values.'''
# Collections of Custom Values
self.dielectricCollection = []
'''If custom values are used for the dielectric constant this will store them to be queried by the custom function'''
self.gibbsCollection = []
'''If custom values are used for the gibbs of water this will store them to be queried by the custom function'''
self.densityCollection = []
'''If custom values are used for the density of water this will store them to be queried by the custom function'''
# Calculated Matrices
self.gasInpGibbs = []
'''Used for debugging, stores the free energy changes of gases'''
self.aqInpGibbs = []
'''Used for debugging, stores the free energy changes of aqueous inputs'''
self.gasInpV = []
'''Used for debugging, stores the volume changes of gasseous inputs'''
self.aqInpV = []
'''Used for debugging, stores the volume changes of aqueous inputs'''
self.gasOutGibbs = []
'''Used for debugging, stores the free energy changes of gasseous inputs'''
self.aqOutGibbs = []
'''Used for debugging, stores the free energy changes of aqueous outputs'''
self.gasOutV = []
'''Used for debugging, stores the volume changes of gasseous outputs'''
self.aqOutV = []
'''Used for debugging, stores the volume changes of aqueous outputs'''
#Mineral Matrices
self.mineralInpGibbs = []
'''Used for debugging, stores the free energy changes of mineral inputs'''
self.mineralOutGibbs = []
'''Used for debugging, stores the free energy changes of mineral outputs'''
self.mineralInpV = []
'''Used for debugging, stores the volume changes of mineral inputs'''
self.mineralOutV = []
'''Used for debugging, stores the volume changes of mineral outputs'''
#Water
self.waterInpGibbs = []
'''Used for debugging, stores the free energy changes of water outputs'''
self.waterInpV = []
'''Used for debugging, stores the volume changes of water inputs'''
self.waterOutGibbs = []
'''Used for debugging, stores the free energy changes of water outputs'''
self.waterOutV = []
'''Used for debugging, stores the volume changes of water outputs'''
# Finals Arrays
self.gibbsLst = []
'''A storage variable that lists the gibbs free energy changes. Not sure if necessary'''
self.logK = []
'''Stores the list of all logK values with temperatures and pressures'''
self.vLst = []
'''A storage variable that lists all the volume changes. Not sure if necessary '''
self.delG = []
'''Stores the list of all delG values with temperatures and pressures'''
self.delV = []
'''Stores the list of all delV values with temperatures and pressures'''
# Variables to Help with Plotting
self.pressRed = []
'''Reduced pressure list with no repeats'''
self.tempRed = []
'''Reduced temperature list with no repeats'''
self.pLogK = []
'''LogK split into arrays with respect to the number of isobars'''
self.pDelG = []
'''DelG split into arrays with respect to the number of isobars'''
self.pDelV = []
'''DelV split into arrays with respect to the number of isobars'''
self.tLogK = []
'''LogK split into arrays with respect to the number of isotherms'''
self.tDelG = []
'''DelG split into arrays with respect to the number of isotherms'''
self.tDelV = []
'''DelV split into arrays with respect to the number of isotherms'''
# Variables to run SUPCRTBL
self.proc = None
'''Needed to run supcrt'''
self.pout = None
'''Needed to run supcrt'''
self.pin = None
'''Needed to run supcrt'''
self.supcrtFile = None
'''Stores the most recently run SUPCRT file, or none if none have been run'''
self.supcrtOut = None
'''Stores the output from calculate_supcrt'''
def clear(self):
'''Clears variables'''
self.__init__()
return
def set_inputs(self):
'''Call this to set the input Arrays. This is not dependent on anything else being called first.'''
# A list of integers
intLst = ['1','2','3','4', '5', '6','7', '8', '9', '10', '11']
# Mineral Loop
mineralCount = 0
aqCount = 0
gasCount = 0
self.mineralInputs = []
self.aqueousInputs = []
self.gasInputs = []
self.waterInputs = []
while mineralCount < 15:
mineralCount += 1
validBool = False
while not validBool:
inp = input('Input Mineral Species')
# can insert mineral validation here if possible
if inp in mineralDictionary:
validBool = True
elif inp == "":
validBool = True
else:
print('Your Species is not in the list, please check your spelling')
continue
validBool2 = False
while not validBool2:
inp2 = input('Input Mineral Species Multiplier')
if inp2 in intLst:
validBool2 = True
elif inp == "":
validBool2 = True
else:
print('Your multiplier is invalid, please check to make sure this is an integer')
if inp == "":
break
self.mineralInputs.append([inp, inp2])
while aqCount <15:
aqCount += 1
validBool = False
while not validBool:
inp = input('Input Aqueous Species')
if inp in nameLst:
validBool = True
elif inp == "":
validBool = True
else:
print('Your Species is not in the list, please check your spelling')
continue
validBool2 = False
if validBool:
while not validBool2:
inp2 = input('Input Aqueous Species Multiplier')
if inp2 in intLst:
validBool2 = True
elif inp == "":
validBool2 = True
else:
print('Your multiplier is invalid, please check to make sure this is an integer')
if inp == "":
break
self.aqueousInputs.append([inp, inp2])
while gasCount < 15:
gasCount += 1
validBool = False
while not validBool:
inp = input('Input Gas Species')
if inp in GasLst:
validBool = True
elif inp == "":
validBool = True
else:
print('Your Species is not in the list, please check your spelling')
continue
if validBool:
validBool2 = False
while not validBool2:
inp2 = input('Input Gas Species Multiplier')
if inp2 in intLst:
validBool2 = True
elif inp == "":
validBool2 = True
else:
print('Your multiplier is invalid, please check to make sure this is an integer')
if inp == "":
break
self.gasInputs.append([inp, inp2])
# Water
validBool3 = False
while not validBool3:
inpWater = input('Would you like to use water? (yes/no)')
if inpWater in ['yes', 'no']:
validBool3 = True
else:
print('Please answer yes or no')
continue
if inpWater == 'yes':
validBool3 = False
while not validBool3:
m3 = input('Enter enter water Multiplier')
if m3 in intLst:
validBool3 = True
else:
print('Please enter a valid integer multiplier ')
else:
m3 = 0
self.waterInputs.append([inpWater, m3])
return
def set_outputs(self):
'''Call this to set the output Arrays. This is not dependent on anything else being called first.'''
# A list of integers
intLst = ['1','2','3','4', '5', '6','7', '8', '9', '10', '11']
# Mineral Loop
mineralCount = 0
aqCount = 0
gasCount = 0
self.mineralOutputs = []
self.aqueousOutputs = []
self.gasOutputs = []
self.waterOutputs = []
while mineralCount < 15:
mineralCount += 1
validBool = False
while not validBool:
inp = input('Output Mineral Species')
# can insert mineral validation here if possible
validBool = True
validBool2 = False
while not validBool2:
inp2 = input('Output Mineral Species Multiplier')
if inp2 in intLst:
validBool2 = True
elif inp == "":
validBool2 = True
else:
print('Your multiplier is invalid, please check to make sure this is an integer')
if inp == "":
break
self.mineralOutputs.append([inp, inp2])
while aqCount <15:
aqCount += 1
validBool = False
while not validBool:
inp = input('Output Aqueous Species')
if inp in nameLst:
validBool = True
elif inp == "":
validBool = True
else:
print('Your Species is not in the list, please check your spelling')
continue
validBool2 = False
if validBool:
while not validBool2:
inp2 = input('Output Aqueous Species Multiplier')
if inp2 in intLst:
validBool2 = True
elif inp == "":
validBool2 = True
else:
print('Your multiplier is invalid, please check to make sure this is an integer')
if inp == "":
break
self.aqueousOutputs.append([inp, inp2])
while gasCount < 15:
gasCount += 1
validBool = False
while not validBool:
inp = input('Input Gas Species')
if inp in GasLst:
validBool = True
elif inp == "":
validBool = True
else:
print('Your Species is not in the list, please check your spelling')
continue
validBool2 = False
if validBool:
while not validBool2:
inp2 = input('Input Gas Species Multiplier')
if inp2 in intLst:
validBool2 = True
elif inp == "":
validBool2 = True
else:
print('Your multiplier is invalid, please check to make sure fthis is an integer')
if inp == "":
break
self.gasOutputs.append([inp, inp2])
# Water
validBool3 = False
while not validBool3:
outWater = input('Would you like to use water in the output? (yes/no)')
if outWater in ['yes', 'no']:
validBool3 = True
else:
print('Please answer yes or no')
if outWater == 'yes':
validBool3 = False
while not validBool3:
m3 = input('Enter enter water Multiplier')
if m3 in intLst:
validBool3 = True
else:
print('Please enter a valid integer multiplier ')
else:
m3 = 0
self.waterOutputs.append([outWater, m3])
return
def set_preferences(self):
'''A function that prompts for user inputs. This is not dependent on anything else being called first. Defaults
are set to be identical to the example calculation on the Deep Earth Water Model Excel Sheet.'''
validBool = False
while not validBool:
ptInp = input('Which P-T input would you like to use? "Custom", "Regular", or "Psat"')
if ptInp in ['Custom', 'Regular', 'Psat']:
validBool = True
self.ptInput = ptInp
else:
print('Please enter one of the provided options')
validBool = False
while not validBool:
RhoOfwater = input('Which density of water would you like to use? "Z&D 2005", "Z&D 2009", or "Custom"')
if RhoOfwater in ['Z&D 2005', 'Z&D 2009', 'Custom']:
validBool = True
self.RhoOfWater = RhoOfwater
else:
print('Please enter one of the provided options')
validBool = False
while not validBool:
force = input('Force Custom? (yes/no)')
if force == 'yes':
validBool = True
elif force == 'no':
validBool = True
self.forceCustom = False
else:
print('Please enter one of the provided options')
validBool = False
while not validBool:
dia = input('Dielectric Constant Equation Option: "Supcrt", "Franck", "Fernandez", "Sverjensky", or "Custom"')
if dia in ['Supcrt', 'Franck', 'Fernandez', 'Sverjensky','Custom']:
validBool = True
self.dielectricEq = dia
else:
print('Please enter one of the provided options')
validBool = False
while not validBool:
forceS = input('Force Supcrt? (yes/no)')
if forceS == 'yes':
validBool = True
elif forceS == 'no':
validBool = True
self.ForceSupcrt = False
else:
print('Please enter one of the provided options')
validBool = False
while not validBool:
freeE = input('Water Free Energy Equation Option: "D&H 1978", "Integral", "Custom"')
if freeE in ['D&H 1978', 'Integral', 'Custom']:
validBool = True
self.WaterFreeEq = freeE
validBool = False
while not validBool:
dispO = input('Display Volume Option? (yes/no)')
if dispO == 'yes':
validBool = True
elif dispO == 'no':
validBool = True
self.DisplayVolOpt = False
else:
print('Please enter one of the provided options')
validBool = False
while not validBool:
PsatdispO = input('Psat Display Volume Option? (yes/no)')
if PsatdispO == 'yes':
validBool = True
elif PsatdispO == 'no':
validBool = True
self.PsatDisplayVol = False
else:
print('Please enter one of the provided options')
validBool = False
while not validBool:
dispV = input('Display Volume? (yes/no)')
if dispV == 'yes':
validBool = True
elif dispV == 'no':
validBool = True
self.DisplayVol = False
else:
print('Please enter one of the provided options')
if self.WaterFreeEq == "Custom" or self.dielectricEq == "Custom" or self.RhoOfWater == "Custom":
self.dielectricCollection, self.densityCollection, self.gibbsCollection = self.import_custom_sheets()
return
def import_custom_sheets(self):
'''A helper function to import custom data from the Deep Earth Water Model.
This only currently works for an unmodified Deep Earth Water Model Sheet format (6_23_20).
This is not dependent on anything else being called first.'''
diaL = pd.read_csv(diePath, header = None)
dia = diaL.to_numpy()
dia = dia[4:, 1:]
diaTrim = dia[1:, 1:]
diaCollection = []
for row in range(len(diaTrim)):
for pressure in range(len(diaTrim[0])):
# in form pressure, temperature, value
diaCollection.append([dia[0][pressure + 1], dia[row + 1][0], diaTrim[row][pressure]])
watDen = pd.read_csv(denPath, header = None)
w = watDen.to_numpy()
w = w[4:, 1:]
wTrim = w[1:,1:]
watDenCollection = []
for row in range(len(wTrim)):
for pressure in range(len(wTrim[0])):
# in form pressure, temperature, value
watDenCollection.append([w[0][pressure + 1], w[row + 1][0], wTrim[row][pressure]])
gibbsOfWater = pd.read_csv(gPath, header = None)
gibbs = gibbsOfWater.to_numpy()
gibbs = gibbs[3:,:]
gibbsTrim = gibbs[1:, 1:]
gibbsCollection = []
for row in range(len(gibbsTrim)):
for pressure in range(len(gibbsTrim[0])):
# in form pressure, temperature, value
gibbsCollection.append([gibbs[0][pressure + 1], gibbs[row + 1][0], gibbsTrim[row][pressure]])
return diaCollection, watDenCollection, gibbsCollection
def set_TPRho(self):
'''Sets arrays of temperature, pressure, water density, and Q to be used in the model based on user input.
Requires that the input and output arrays have been set up otherwise it will return a divide by 0 error in the
calculations.'''
pressArr = []
tempArr = []
self.RhoWatArr = []
self.DiaArr = []
self.QArr =[]
self.gibbsLst = []
self.logK = []
self.vLst = []
self.delG = []
self.delV = []
if self.ptInput == "Custom":
ptSheet = pd.read_csv(inpPath,encoding= 'unicode_escape', header = None)
ptFinder = ptSheet.to_numpy()
tempArr = [float(i[1]) for i in ptFinder[4:]]
pressArr = [float(i[0]) for i in ptFinder[4:]]
elif self.ptInput == "Regular":
validBool = False
while not validBool:
try:
templow = int(input('Input the minimum temperature'))
temphigh = int(input('Input the maximum temperature'))
tempstep = int(input('Input the temperature step'))
pmin = float(input('Input the minimum pressure (Kb)'))
pmax = float(input('Input the maximum pressure (Kb)'))
pstep = float(input('Input the pressure step (Kb)'))
validBool = True
except ValueError:
print('You have entered a non-integer value, please start again')
tempArr = np.arange(start= templow, stop = temphigh + .00001, step = tempstep)
parrHelp = np.arange(start= pmin, stop = pmax + .00001, step = pstep)
for i in range(len(parrHelp)):
pressArr.append([parrHelp[i]]* len(tempArr))
pressArr = np.multiply(pressArr, 1000)
tempArr = [tempArr] * len(parrHelp)
elif self.ptInput == "Psat":
validBool = False
while not validBool:
try:
templow = int(input('Input the minimum temperature'))
temphigh = int(input('Input the mamximum temperature'))
tempstep = int(input('Input the temperature step'))
validBool = True
except ValueError:
print('You have entered a non-integer value, please start again')
tempArr = np.arange(start= templow, stop = temphigh + 1, step = tempstep)
for i in range(len(tempArr)):
if tempArr[i] < 100:
pressArr.append(1)
else:
pressArr.append(2.1650906415E-11*np.double(tempArr[i])**5 + 0.0008467019353*np.double(tempArr[i])**2 - 0.17973651666*tempArr[i] + 10.7768850763807)
else:
# If I've done the checking correctly above it should never reach this
raise ValueError("You have not set your options yet, please set them before continuing")
self.tempUsed = np.ndarray.flatten(np.asarray(tempArr))
self.pressureUsed = np.ndarray.flatten(np.asarray(pressArr))
self.tKelvin = np.add(self.tempUsed, 273.15)
# code to set options in a way the equations can understand
if self.ptInput == "Psat":
self.psat = True
else:
self.psat = False
if self.RhoOfWater =='Z&D 2005':
self.equation = 1
elif self.RhoOfWater == 'Z&D 2009':
self.equation = 2
else:
self.equation = 3
if self.dielectricEq == "Supcrt":
self.diaEq = 1
elif self.dielectricEq == "Franck":
self.diaEq = 2
elif self.dielectricEq == "Fernandez":
self.diaEq = 3
elif self.dielectricEq == "Sverjensky":
self.diaEq = 4
else:
self.diaEq = 5
# write code to take in custom Rho, G, and Water Values here
self.densityCollection = np.asarray(self.densityCollection).astype(float)
self.dielectricCollection = np.asarray(self.dielectricCollection).astype(float)
self.gibbsCollection = np.asarray(self.gibbsCollection).astype(float)
# Sets the water density array
for i in range(len(self.pressureUsed)):
# For the custom array
if self.RhoOfWater =="Custom" or (self.forceCustom == True and self.pressureUsed[i] < 1000):
idx = np.intersect1d(np.where(np.asarray(self.densityCollection) == self.pressureUsed[i]/1000), np.where(np.asarray(self.densityCollection) == self.tempUsed[i]))[0]
if not np.isnan(self.densityCollection[idx][2]):
self.RhoWatArr.append(self.densityCollection[idx][2])
else:
self.RhoWatArr.append(0)
else:
self.RhoWatArr.append(DEWEquations.DEWEquations.calculateDensity(self.pressureUsed[i], self.tempUsed[i], self.equation, 0.01, self.psat))
# Sets the dielectric constant array
for i in range(len(self.pressureUsed)):
# for the custom array
if self.dielectricEq == "Custom":
idx = np.intersect1d(np.where(np.asarray(self.dielectricCollection) == self.pressureUsed[i]/1000), np.where(np.asarray(self.dielectricCollection) == self.tempUsed[i]))[0]
if not np.isnan(self.dielectricCollection[idx][2]):
self.DiaArr.append(self.dielectricCollection[idx][2])
else:
self.DiaArr.append(0)
else:
if self.ForceSupcrt == True and self.pressureUsed[i] < 5000 and self.psat == False:
self.DiaArr.append(DEWEquations.DEWEquations.calculateEpsilon(self.RhoWatArr[i], self.tempUsed[i], 1, self.psat))
else:
self.DiaArr.append(DEWEquations.DEWEquations.calculateEpsilon(self.RhoWatArr[i], self.tempUsed[i], self.diaEq, self.psat))
### The function works up until this point, I haven't debugged further yet (6_29_20) ###
# Sets up the Q array
for i in range(len(self.pressureUsed)):
if self.DisplayVol == True:
try:
# Has issues with some Q, not sure if problematic
self.QArr.append(float(DEWEquations.DEWEquations.calculateQ(self.pressureUsed[i], self.tempUsed[i], self.RhoWatArr[i], self.equation, self.diaEq, self.psat))*np.double(10)**6)
except:
self.QArr.append(0)
else:
self.QArr.append(0)
# Sets up custom Gibbs of Water Array:
if self.WaterFreeEq == "Custom":
for i in range(len(self.pressureUsed)):
idx = np.intersect1d(np.where(np.asarray(self.gibbsCollection) == self.pressureUsed[i]/1000), np.where(np.asarray(self.gibbsCollection) == self.tempUsed[i]))[0]
if not np.isnan(self.gibbsCollection[idx][2]):
self.GibbsH2O.append(self.gibbsCollection[idx][2])
else:
self.GibbsH2O.append(0)
return
def calculate_matrices(self):
'''A helper function to aggregate the values to the input and output matrices.
It requires both the input and output arrays to be set up to function. It is called within "calculate"'''
self.inAqMat = []
self.inGasMat = []
self.outAqMat = []
self.outGasMat = []
for i in self.aqueousInputs:
self.inAqMat.append([i[0],symbolDict[i[0]], delGf[i[0]], delHf[i[0]], entropy[i[0]],volume[i[0]],specHeat[i[0]],
a1x10[i[0]], a2x10_2[i[0]], a3[i[0]],a4x10_4[i[0]],c1[i[0]],c2x10_4[i[0]],omegax10_5[i[0]],Z[i[0]], i[1]])
for i in self.gasInputs:
self.inGasMat.append([i[0],GasSymb[i[0]],GasDelGf[i[0]],GasDelHf[i[0]],GasEntropy[i[0]],GasCp[i[0]], GasA[i[0]],
GasBx103[i[0]],GasCx10_5[i[0]],GasT[i[0]], i[1]])
for i in self.aqueousOutputs:
self.outAqMat.append([i[0],symbolDict[i[0]], delGf[i[0]], delHf[i[0]], entropy[i[0]],volume[i[0]],specHeat[i[0]],
a1x10[i[0]], a2x10_2[i[0]], a3[i[0]],a4x10_4[i[0]],c1[i[0]],c2x10_4[i[0]],omegax10_5[i[0]],Z[i[0]], i[1]])
for i in self.gasOutputs:
self.outGasMat.append([i[0],GasSymb[i[0]],GasDelGf[i[0]],GasDelHf[i[0]],GasEntropy[i[0]],GasCp[i[0]], GasA[i[0]],
GasBx103[i[0]],GasCx10_5[i[0]],GasT[i[0]],i[1]])
return
def calculate_gas(self):
'''A helper function to calculate the gasseous columns and output them as a matrix. Specifically returns the arrays
gasInGibbs, gasOutGibbs, gasInV, gasOuV. Needs self.tempUsed and self.tKelvin to be set, as well as the input gas matrix.
It is called within the calculate function.'''
gasInGibbs = []
gasOuGibbs = []
gasInV = []
gasOuV = []
for gas in self.inGasMat:
storelst = []
storelst2 =[]
storelst.append(gas[0])
storelst.append(gas[10])
storelst2.append(gas[0])
storelst2.append(gas[10])
for i in range(len(self.tempUsed)):
if self.DisplayVol == False or self.tempUsed[i] == 0:
storelst2.append(0)
else:
storelst2.append(24.465)
for i in range(len(self.tKelvin)):
storelst.append(gas[2] - gas[4]*(self.tKelvin[i]-T_r) + gas[6]*(self.tKelvin[i]-T_r - self.tKelvin[i]*np.log(self.tKelvin[i]/T_r)) + gas[7]*(0.001)/2*(2*self.tKelvin[i]*T_r -np.double(self.tKelvin[i])**2 - np.double(T_r) **2) + gas[8]*100000*(np.double(self.tKelvin[i])**2 + np.double(T_r)**2 -2*self.tKelvin[i]*T_r)/(2*self.tKelvin[i]*np.double(T_r)**2))
gasInGibbs.append(storelst)
gasInV.append(storelst2)
for gas in self.outGasMat:
storelst = []
storelst2 = []
storelst.append(gas[0])
storelst.append(gas[10])
storelst2.append(gas[0])
storelst2.append(gas[10])
for i in range(len(self.tempUsed)):
if self.DisplayVol == False or self.tempUsed[i] == 0:
storelst2.append(0)
else:
storelst2.append(24.465)
for i in range(len(self.tKelvin)):
storelst.append(gas[2] - gas[4]*(self.tKelvin[i]-T_r) + gas[6]*(self.tKelvin[i]-T_r - self.tKelvin[i]*np.log(self.tKelvin[i]/T_r)) + gas[7]*(0.001)/2*(2*self.tKelvin[i]*T_r -np.double(self.tKelvin[i])**2 - np.double(T_r) **2) + gas[8]*100000*(np.double(self.tKelvin[i])**2 + np.double(T_r)**2 -2*self.tKelvin[i]*T_r)/(2*self.tKelvin[i]*np.double(T_r)**2))
gasOuGibbs.append(storelst)
gasOuV.append(storelst2)
if len(gasInGibbs) == 0:
gasInGibbs = [np.zeros(len(self.tKelvin) + 2)]
if len(gasOuGibbs) == 0:
gasOuGibbs = [np.zeros(len(self.tKelvin) + 2)]
if len(gasInV) == 0:
gasInV = [np.zeros(len(self.tKelvin) + 2)]
if len(gasOuV) == 0:
gasOuV = [np.zeros(len(self.tKelvin) + 2)]
return gasInGibbs, gasOuGibbs, gasInV, gasOuV
def calculate_H2O(self):
'''This function requires input and output matrices to be set. This is called within the calculate function.'''
waterMatInGibbs = []
waterMatOutGibbs = []
waterMatInV = []
waterMatOutV = []
if self.WaterFreeEq == 'D&H 1978':
self.waterDensity = 1
elif self.WaterFreeEq == 'Integral':
self.waterDensity = 2
else:
self.waterDensity = 3
if self.waterInputs[0][0] == 'yes':
waterLst = []
waterLst2 = []
waterLst.append('H2O')
waterLst.append(self.waterInputs[0][1])
waterLst2.append('H2O')
waterLst2.append(self.waterInputs[0][1])
for i in range(len(self.pressureUsed)):
#for i in range(len(self.pressureUsed)):
if self.WaterFreeEq == 'Custom':
try:
if self.GibbsH2O[i] == 0:
waterLst.append(0)
else:
waterLst.append(GibbsH2O[i])
except:
waterLst.append(GibbsH2O[i])
else:
store = DEWEquations.DEWEquations.calculateGibbsOfWater(self.pressureUsed[i], self.tempUsed[i], self.waterDensity, self.equation, self.psat)
waterLst.append(store)
if self.DisplayVol == True:
try:
waterLst2.append(18.01528/self.RhoWatArr[i])
except:
waterLst2.append(0)
continue
else:
waterLst2.append(0)
waterMatInGibbs.append(waterLst)
waterMatInV.append(waterLst2)
if self.waterOutputs[0][0] =='yes':
waterLst = []
waterLst2 = []
waterLst.append('H2O')
waterLst.append(self.waterOutputs[0][1])
waterLst2.append('H2O')
waterLst2.append(self.waterOutputs[0][1])
for i in range(len(self.pressureUsed)):
if self.WaterFreeEq == 'Custom':
try:
if GibbsH2O[i] == 0:
waterLst.append(0)
else:
waterLst.append(GibbsH2O[i])
except:
waterLst.append(GibbsH2O[i])
else:
waterLst.append(DEWEquations.DEWEquations.calculateGibbsOfWater(self.pressureUsed[i], self.tempUsed[i], self.waterDensity, self.equation, self.psat))
if self.DisplayVol == True:
try:
waterLst2.append(18.01528/self.RhoWatArr[i])
except:
waterLst2.append(0)
else:
waterLst2.append(0)
waterMatOutGibbs.append(waterLst)
waterMatOutV.append(waterLst2)
if len(waterMatInGibbs) == 0:
waterMatInGibbs = np.zeros((len(self.tKelvin) + 2))
if len(waterMatInV) == 0:
waterMatInV = np.zeros((len(self.tKelvin) + 2))
if len(waterMatOutGibbs) == 0:
waterMatOutGibbs = np.zeros((len(self.tKelvin) + 2))
if len(waterMatOutV) == 0:
waterMatOutV = np.zeros((len(self.tKelvin) + 2))
return waterMatInGibbs, waterMatInV, waterMatOutGibbs, waterMatOutV
def calculate_aq(self):
'''A helper function to calculate the aqueous columns and output them as a matrix. This is called within calculate.'''
aqInGibbs = []
aqOuGibbs = []
aqInV = []
aqOuV = []
for aq in self.inAqMat:
storelst = []
storelst2= []
storelst.append(aq[0])
storelst.append(aq[15])
storelst2.append(aq[0])
storelst2.append(aq[15])
for i in range(len(self.tKelvin)):
storelst.append(aq[2] - aq[4] * (self.tKelvin[i] - T_r)
- aq[11] * (self.tKelvin[i] * np.log(self.tKelvin[i]/T_r) - self.tKelvin[i] + T_r)
- aq[12]*(10**4)*(((1/(self.tKelvin[i]-Theta)) - (1/(T_r-Theta)))*((Theta-self.tKelvin[i])/(Theta))- (self.tKelvin[i]/(Theta*Theta)) * np.log((T_r*(self.tKelvin[i]-Theta))/(self.tKelvin[i]*(T_r-Theta))))
+ aq[7]*(10**-1)*(self.pressureUsed[i]-Pr)
+ aq[8]*(10**2)*np.log((Psy+self.pressureUsed[i])/(Psy+Pr))
+ (1/(self.tKelvin[i]-Theta))*(aq[9]*(self.pressureUsed[i]-Pr)
+ aq[10]*(10**4)*np.log((Psy+self.pressureUsed[i])/(Psy+Pr)))
+ DEWEquations.DEWEquations.calculateOmega(self.pressureUsed[i],self.tempUsed[i],self.RhoWatArr[i],aq[0],aq[13]*(10**5),aq[14])*((1/self.DiaArr[i])-1)
- aq[13]*(10**5)*((1/E_PrTr)-1)
+ aq[13]*(10**5)*Upsilon*(self.tKelvin[i]-T_r))
for i in range(len(self.pressureUsed)):
storelst2.append((aq[7]/10 + aq[8]*100/(Psy+self.pressureUsed[i])
+ (aq[9] + aq[10]*10000/(Psy+self.pressureUsed[i]))/(self.tKelvin[i]-Theta)
- DEWEquations.DEWEquations.calculateOmega(self.pressureUsed[i],self.tempUsed[i],self.RhoWatArr[i],aq[0],aq[13]*(10**5),aq[14])*(self.QArr[i]*10**-6 )
+ (1/self.DiaArr[i] - 1) * DEWEquations.DEWEquations.calculate_domegadP(self.pressureUsed[i],self.tempUsed[i],self.RhoWatArr[i],aq[0],aq[13]*(10**5),aq[14],self.equation,self.psat))*41.84)
aqInGibbs.append(storelst)
aqInV.append(storelst2)
for aq in self.outAqMat:
storelst = []
storelst2= []
storelst.append(aq[0])
storelst.append(aq[15])
storelst2.append(aq[0])
storelst2.append(aq[15])
for i in range(len(self.tKelvin)):
storelst.append(aq[2] - aq[4] * (self.tKelvin[i] - T_r)
- aq[11] * (self.tKelvin[i] * np.log(self.tKelvin[i]/T_r) - self.tKelvin[i] + T_r)
- aq[12]*(10**4)*(((1/(self.tKelvin[i]-Theta)) - (1/(T_r-Theta)))*((Theta-self.tKelvin[i])/(Theta))- (self.tKelvin[i]/(Theta*Theta)) * np.log((T_r*(self.tKelvin[i]-Theta))/(self.tKelvin[i]*(T_r-Theta))))
+ aq[7]*(10**-1)*(self.pressureUsed[i]-Pr)
+ aq[8]*(10**2)*np.log((Psy+self.pressureUsed[i])/(Psy+Pr))
+ (1/(self.tKelvin[i]-Theta))*(aq[9]*(self.pressureUsed[i]-Pr)
+ aq[10]*(10**4)*np.log((Psy+self.pressureUsed[i])/(Psy+Pr)))
+ DEWEquations.DEWEquations.calculateOmega(self.pressureUsed[i],self.tempUsed[i],self.RhoWatArr[i],aq[0],aq[13]*(10**5),aq[14])*((1/self.DiaArr[i])-1)
- aq[13]*(10**5)*((1/E_PrTr)-1)
+ aq[13]*(10**5)*Upsilon*(self.tKelvin[i]-T_r))
for i in range(len(self.pressureUsed)):
storelst2.append((aq[7]/10 + aq[8]*100/(Psy+self.pressureUsed[i])
+ (aq[9] + aq[10]*10000/(Psy+self.pressureUsed[i]))/(self.tKelvin[i]-Theta)
- DEWEquations.DEWEquations.calculateOmega(self.pressureUsed[i],self.tempUsed[i],self.RhoWatArr[i],aq[0],aq[13]*(10**5),aq[14])*(self.QArr[i]*10**-6 )
+ (1/self.DiaArr[i] - 1) * DEWEquations.DEWEquations.calculate_domegadP(self.pressureUsed[i],self.tempUsed[i],self.RhoWatArr[i],aq[0],aq[13]*(10**5),aq[14],self.equation,self.psat))*41.84)
aqOuGibbs.append(storelst)
aqOuV.append(storelst2)
if len(aqInGibbs) == 0:
aqInGibbs = [np.zeros(len(self.tKelvin) + 2)]
if len(aqOuGibbs) == 0:
aqOuGibbs = [np.zeros(len(self.tKelvin) + 2)]
if len(aqInV) == 0:
aqInV = [np.zeros(len(self.tKelvin) + 2)]
if len(aqOuV) == 0:
aqOuV = [np.zeros(len(self.tKelvin) + 2)]
return aqInGibbs, aqOuGibbs, aqInV, aqOuV
def calculate(self):
'''The function called that will update all of the parameters. It has no outputs, but allows certain arrays to be queried.
'''
self.calculate_matrices()
self.waterInpGibbs, self.waterInpV, self.waterOutGibbs, self.waterOutV = self.calculate_H2O()
self.aqInpGibbs, self.aqOutGibbs, self.aqInpV, self.aqOutV = self.calculate_aq()
self.gasInpGibbs, self.gasOutGibbs, self.gasInpV, self.gasOutV = self.calculate_gas()
G1 = np.delete(np.asarray(self.waterInpGibbs), [0,1]).astype(np.float) * int(self.waterInputs[0][1])
V1 = np.delete(np.asarray(self.waterInpV), [0,1]).astype(np.float) * int(self.waterInputs[0][1])
G4 = np.delete(np.asarray(self.waterOutGibbs), [0,1]).astype(np.float) * int(self.waterOutputs[0][1])
V4 = np.delete(np.asarray(self.waterOutV), [0,1]).astype(np.float) * int(self.waterOutputs[0][1])
# Gas Loops
G3, V3 = ([], [])
for i in range(len(self.gasInpGibbs)):
G3.append(np.multiply(np.delete(np.asarray(self.gasInpGibbs[i]), [0,1]).astype(np.float), int(self.gasInpGibbs[i][1])))
V3.append(np.multiply(np.delete(np.asarray(self.gasInpV[i]), [0,1]).astype(np.float), int(self.gasInpV[i][1])))
G3 = np.sum(G3, axis = 0)
V3 = np.sum(V3, axis = 0)
G6, V6 = ([], [])
for i in range(len(self.gasOutGibbs)):
G6.append(np.multiply(np.delete(np.asarray(self.gasOutGibbs[i]), [0,1]).astype(np.float), int(self.gasOutGibbs[i][1])))
V6.append(np.multiply(np.delete(np.asarray(self.gasOutV[i]), [0,1]).astype(np.float), int(self.gasOutV[i][1])))
G6 = np.sum(G6, axis = 0)
V6 = np.sum(V6, axis = 0)
# Aqueous Inputs
G2, V2 = ([], [])
for i in range(len(self.aqInpGibbs)):
G2.append(np.multiply(np.delete(np.asarray(self.aqInpGibbs[i]), [0,1]).astype(np.float), int(self.aqInpGibbs[i][1])))
V2.append(np.multiply(np.delete(np.asarray(self.aqInpV[i]), [0,1]).astype(np.float), int(self.aqInpV[i][1])))
G2 = np.sum(G2, axis = 0)
V2 = np.sum(V2, axis = 0)
G5, V5 = ([], [])
for i in range(len(self.aqOutGibbs)):
G5.append(np.multiply(np.delete(np.asarray(self.aqOutGibbs[i]), [0,1]).astype(np.float), int(self.aqOutGibbs[i][1])))
V5.append(np.multiply(np.delete(np.asarray(self.aqOutV[i]), [0,1]).astype(np.float), int(self.aqOutV[i][1])))
G5 = np.sum(G5, axis = 0)
V5 = np.sum(V5, axis = 0)
dG = [np.sum([G4, G5, G6], axis = 0) - np.sum([G1, G2, G3], axis = 0)]
dV = [np.sum([V4, V5, V6], axis = 0) - np.sum([V1, V2, V3], axis = 0)]
# Adding the mineral contributions if they exist, must be at the same temperatures and pressures
if len(self.mineralInputs) > 0:
for i in range(len(self.mineralInputs)):
if self.psat == False:
myMinPath = mineralDictionary2
else:
myMinPath = mineralDictionary
for temp in self.tempUsed:
self.mineralInpGibbs.append(np.multiply(myMinPath[self.mineralInputs[i][0]]['delG'][myMinPath[self.mineralInputs[i][0]]['Temperature'].index(temp)], int(self.mineralInputs[i][1])))
self.mineralInpV.append(np.multiply(myMinPath[self.mineralInputs[i][0]]['delV'][myMinPath[self.mineralInputs[i][0]]['Temperature'].index(temp)], int(self.mineralInputs[i][1])))
dG = np.sum([dG, np.sum([self.mineralInpGibbs], axis = 0)], axis = 0)
dV = np.sum([dV, np.sum([self.mineralInpV], axis = 0)], axis = 0)
if len(self.mineralOutputs) > 0:
for i in range(len(self.mineralOutputs)):
for temp in self.tempUsed:
self.mineralOutGibbs.append(np.multiply(myMinPath[self.mineralOutputs[i][0]]['delG'][myMinPath[self.mineralOutputs[i][0]]['Temperature'].index(temp)], int(self.mineralInputs[i][1])))
self.mineralOutV.append(np.multiply(myMinPath[self.mineralOutputs[i][0]]['delV'][myMinPath[self.mineralOutputs[i][0]]['Temperature'].index(temp)], int(self.mineralInputs[i][1])))
dG = np.sum([dG, -np.sum([self.mineralOutGibbs],axis = 0)], axis = 0)
dV = np.sum([dV, -np.sum([self.mineralOutV],axis = 0)], axis = 0)
self.logK = []
self.delG = []
self.delV = []
for i in range(len(dG[0])):
self.logK.append([-dG[0][i]/(2.302585*self.tKelvin[i]*bigR), self.tempUsed[i], self.pressureUsed[i]])
self.delG.append([dG[0][i], self.tempUsed[i], self.pressureUsed[i]])
self.delV.append([dV[0][i], self.tempUsed[i], self.pressureUsed[i]])
# Sets plotting arrays for convenient plotting of isotherms/isobars
if self.ptInput!= 'Psat' or self.psat == False:
self.pressRed = list(set(self.pressureUsed))
self.tempRed = list(set(self.tempUsed))
self.pressRed.sort()
self.tempRed.sort()
temppLogK = defaultdict(list)
temppDelG = defaultdict(list)
temppDelV = defaultdict(list)
temptLogK = defaultdict(list)
temptDelG = defaultdict(list)
temptDelV = defaultdict(list)
for logK, temp, pressure in self.logK:
temppLogK[pressure].append(logK)
temptLogK[temp].append(logK)
for delG, temp, pressure in self.delG:
temppDelG[pressure].append(delG)
temptDelG[temp].append(delG)
for delV, temp, pressure in self.delV:
temppDelV[pressure].append(delV)
temptDelV[temp].append(delV)
for item in temppDelG:
self.pDelG.append(temppDelG[item])
for item in temppDelV:
self.pDelV.append(temppDelV[item])
for item in temppLogK:
self.pLogK.append(temppLogK[item])
for item in temptDelG:
self.tDelG.append(temptDelG[item])
for item in temptDelV:
self.tDelV.append(temptDelV[item])
for item in temptLogK:
self.tLogK.append(temptLogK[item])
return
###############################
####### Methods to auto #######
###############################
def set_tp(self, pt_arr):
'''Setting the PT values, but automated for the helperfunction. Can also be used to quick set tp with prompted input'''
pressArr = []
tempArr = []
self.RhoWatArr = []
self.DiaArr = []
self.QArr =[]
self.gibbsLst = []
self.logK = []
self.vLst = []
self.delG = []
self.delV = []
if self.ptInput == "Custom":
ptSheet =pd.read_csv(inpPath,encoding= 'unicode_escape', header = None)
ptFinder = ptSheet.to_numpy()
tempArr = [float(i[1]) for i in ptFinder[4:]]
pressArr = [float(i[0]) for i in ptFinder[4:]]
elif self.ptInput == "Regular":
try:
templow = pt_arr[0][0]
temphigh =pt_arr[0][1]
tempstep = pt_arr[0][2]
pmin = pt_arr[1][0]
pmax = pt_arr[1][1]
pstep = pt_arr[1][2]
except ValueError:
print('Your PT array is not formatted correctly. Please use the format [[tmin, tmax, tstep][pmin, pmax, pstep]]')
tempArr = np.arange(start= templow, stop = temphigh + 1, step = tempstep)
parrHelp = np.arange(start= pmin, stop = pmax + 1, step = pstep)
for i in range(len(parrHelp)):
pressArr.append([parrHelp[i]]* len(tempArr))
pressArr = np.multiply(pressArr, 1000)
tempArr = [tempArr] * len(parrHelp)
elif self.ptInput == "Psat":
try:
templow = pt_arr[0]
temphigh = pt_arr[1]
tempstep = pt_arr[2]
validBool = True
except ValueError:
print('Your input is not formatted correctly. Please use the format for psat of [tmin, tmax, tstep]')
tempArr = np.arange(start= templow, stop = temphigh + 1, step = tempstep)
for i in range(len(tempArr)):
if tempArr[i] < 100:
pressArr.append(1)
else:
pressArr.append(2.1650906415E-11*np.double(tempArr[i])**5 + 0.0008467019353*np.double(tempArr[i])**2 - 0.17973651666*tempArr[i] + 10.7768850763807)
else:
# If I've done the checking correctly above it should never reach this
raise ValueError("You have not set your options yet, please set them before continuing")
self.tempUsed = np.ndarray.flatten(np.asarray(tempArr))
self.pressureUsed = np.ndarray.flatten(np.asarray(pressArr))
self.tKelvin = np.add(self.tempUsed, 273.15)
# code to set options in a way the equations can understand
if self.ptInput == "Psat":
self.psat = True
else:
self.psat = False
if self.RhoOfWater =='Z&D 2005':
self.equation = 1
elif self.RhoOfWater == 'Z&D 2009':
self.equation = 2
else:
self.equation = 3
if self.dielectricEq == "Supcrt":
self.diaEq = 1
elif self.dielectricEq == "Franck":
self.diaEq = 2
elif self.dielectricEq == "Fernandez":
self.diaEq = 3
elif self.dielectricEq == "Sverjensky":
self.diaEq = 4
else:
self.diaEq = 5
# write code to take in custom Rho, G, and Water Values here
self.densityCollection = np.asarray(self.densityCollection).astype(float)
self.dielectricCollection = np.asarray(self.dielectricCollection).astype(float)
self.gibbsCollection = np.asarray(self.gibbsCollection).astype(float)
# Sets the water density array
for i in range(len(self.pressureUsed)):
# For the custom array
if self.RhoOfWater =="Custom" or (self.forceCustom == True and self.pressureUsed[i] < 1000):
idx = np.intersect1d(np.where(np.asarray(self.densityCollection).astype(float) == self.pressureUsed[i]/1000), np.where(np.asarray(self.densityCollection).astype(float) == self.tempUsed[i]))[0]
if not np.isnan(self.densityCollection[idx][2]):
self.RhoWatArr.append(self.densityCollection[idx][2])
else:
self.RhoWatArr.append(0)
else:
self.RhoWatArr.append(DEWEquations.DEWEquations.calculateDensity(self.pressureUsed[i], self.tempUsed[i], self.equation, 0.01, self.psat))
# Sets the dielectric constant array
for i in range(len(self.pressureUsed)):
# for the custom array
if self.dielectricEq == "Custom":
idx = np.intersect1d(np.where(np.asarray(self.dielectricCollection).astype(float) == self.pressureUsed[i]/1000), np.where(np.asarray(self.dielectricCollection).astype(float) == self.tempUsed[i]))[0]
if not np.isnan(self.dielectricCollection[idx][2]):
self.DiaArr.append(self.dielectricCollection[idx][2])
else:
self.DiaArr.append(0)
else:
if self.ForceSupcrt == True and self.pressureUsed[i] < 5000 and self.psat == False:
self.DiaArr.append(DEWEquations.DEWEquations.calculateEpsilon(self.RhoWatArr[i], self.tempUsed[i], 1, self.psat))
else:
self.DiaArr.append(DEWEquations.DEWEquations.calculateEpsilon(self.RhoWatArr[i], self.tempUsed[i], self.diaEq, self.psat))
# Sets up the Q array
for i in range(len(self.pressureUsed)):
if self.DisplayVol == True:
try:
self.QArr.append(float(DEWEquations.DEWEquations.calculateQ(self.pressureUsed[i], self.tempUsed[i], self.RhoWatArr[i], self.equation, self.diaEq, self.psat))*np.double(10)**6)
except:
self.QArr.append(0)
else:
self.QArr.append(0)
# Sets up custom Gibbs of Water Array:
if self.WaterFreeEq == "Custom":
for i in range(len(self.pressureUsed)):
idx = np.intersect1d(np.where(np.asarray(self.gibbsCollection).astype(float) == self.pressureUsed[i]/1000), np.where(np.asarray(self.gibbsCollection).astype(float) == self.tempUsed[i]))[0]
if not np.isnan(self.gibbsCollection[idx][2]):
self.GibbsH2O.append(self.gibbsCollection[idx][2])
else:
self.GibbsH2O.append(0)
return
def run(self, pt_arr, min_inp =[], aq_inp = [], g_inp = [], h2o_inp = 0, min_out = [],aq_out =[], g_out = [],h2o_out = 0,
ptInp = 'Psat', rhoWat = 'Z&D 2005', forceBool = False, dieEQ = 'Supcrt', forceSC = True,
WFEQ ='D&H 1978', dsV = True, pdsV = True, DV = True, EQ = 1, dEQ = 1, pst = True, mWn = 1, makeP = False):
if h2o_inp > 0:
self.waterInputs = [['yes',h2o_inp]]
else:
self.waterInputs = [['no',0]]
if h2o_out > 0:
self.waterOutputs = [['yes',h2o_out]]
else:
self.waterOutputs = [['no',0]]
self.mineralInputs = min_inp
self.aqueousInputs = aq_inp
self.gasInputs = g_inp
self.mineralOutputs = min_out
self.aqueousOutputs = aq_out
self.gasOutputs = g_out
self.ptInput = ptInp
self.RhoOfWater = rhoWat
self.forceCustom = forceBool
self.dielectricEq = dieEQ
self.ForceSupcrt = forceSC
self.WaterFreeEq = WFEQ
self.DisplayVolOpt = dsV
self.PsatDisplayVol = pdsV
self.DisplayVol = DV
self.equation = EQ
self.diaEq = dEQ
self.psat = pst
self.waterDensity = mWn
# to actually run:
self.set_tp(pt_arr)
self.calculate()
if makeP == True:
self.make_plots()
return
###### MAKE PLOTS###########
def make_plots(self):
'''A final function that the user calls to make the plots possible in the Excel spreadsheet. '''
plt.clf()
###### PSAT PLOTS #######
if self.psat == True or self.ptInput =='Psat':
plt.figure()
plt.plot(self.pressureUsed, [i[0] for i in self.logK])
plt.xlabel('Pressure (bar)')
plt.ylabel('LogK')
plt.title('Pressure vs. LogK Psat Curve')
plt.show()
plt.figure()
plt.plot(self.pressureUsed, [i[0] for i in self.delG])
plt.xlabel('Pressure (bar)')
plt.ylabel(r'$\Delta$G')
plt.title('Pressure vs. $\Delta$G Psat Curve')
plt.show()
plt.figure()
plt.plot(self.pressureUsed, [i[0] for i in self.delV])
plt.xlabel('Pressure (bar)')
plt.ylabel('$\Delta$V')
plt.title('Pressure vs. $\Delta$V Psat Curve')
plt.show()
plt.figure()
plt.plot(self.tempUsed, [i[0] for i in self.logK])
plt.xlabel(r'Temperature ($^\circ$ C)')
plt.ylabel('LogK')
plt.title('Temperature vs. LogK Psat Curve')
plt.show()
plt.figure()
plt.plot(self.tempUsed, [i[0] for i in self.delG])
plt.xlabel('Temperature ($^\circ$ C)')
plt.ylabel('$\Delta$G')
plt.title('Temperature vs. $\Delta$G Psat Curve')
plt.show()
plt.figure()
plt.plot(self.tempUsed, [i[0] for i in self.delV])
plt.xlabel('Temperature ($^\circ$ C)')
plt.ylabel('$\Delta$V')
plt.title('Temperature vs. $\Delta$V Psat Curve')
plt.show()
####### NON PSAT PLOTS ########
else:
# T Plots
plt.figure()
for i in self.pDelG:
plt.plot(self.tempRed, i)
plt.legend(self.pressRed,bbox_to_anchor=(1.05, 1), title = 'Pressure (bar)', loc='upper left')
plt.xlabel('Temperature ($^\circ$C)')
plt.ylabel('$\Delta$G')
plt.title('Temperature vs. $\Delta$G')
plt.show()
plt.figure()
for i in self.pDelV:
plt.plot(self.tempRed, i)
plt.legend(self.pressRed,bbox_to_anchor=(1.05, 1), title = 'Pressure (bar)', loc='upper left')
plt.xlabel('Temperature ($^\circ$C)')
plt.ylabel('$\Delta$V')
plt.title('Temperature vs. $\Delta$V')
plt.show()
plt.figure()
for i in self.pLogK:
plt.plot(self.tempRed, i)
plt.legend(self.pressRed,bbox_to_anchor=(1.05, 1), title = 'Pressure (bar)', loc='upper left')
plt.xlabel('Temperature ($^\circ$C)')
plt.ylabel('LogK')
plt.title('Temperature vs. LogK')
plt.show()
# P Plots
plt.figure()
for i in self.tDelG:
plt.plot(self.pressRed, i)
plt.legend(self.tempRed,bbox_to_anchor=(1.05, 1), title = 'Temperature ($^\circ$C)', loc='upper left')
plt.xlabel('Pressure (bar)')
plt.ylabel('$\Delta$G')
plt.title('Pressure vs. $\Delta$G')
plt.show()
plt.figure()
for i in self.tDelV:
plt.plot(self.pressRed, i)
plt.legend(self.tempRed,bbox_to_anchor=(1.05, 1), title = 'Temperature ($^\circ$C)', loc='upper left')
plt.xlabel('Pressure (bar)')
plt.ylabel('$\Delta$V')
plt.title('Pressure vs. $\Delta$V')
plt.show()
plt.figure()
for i in self.tLogK:
plt.plot(self.pressRed, i)
plt.legend(self.tempRed,bbox_to_anchor=(1.05, 1), title = 'Temperature ($^\circ$C)', loc='upper left')
plt.xlabel('Pressure (bar)')
plt.ylabel('LogK')
plt.title('Pressure vs. LogK')
plt.show()
return
#############################
######### OTHER #############
#############################
def export_to_csv(self):
dV = [row[0] for row in self.delV]
dG = [row[0] for row in self.delG]
lK = [row[0] for row in self.logK]
T = [row[1] for row in self.logK]
P = [row[2] for row in self.logK]
output_array = np.column_stack([T,P, dV,dG,lK])
df = pd.DataFrame(output_array)
df.columns = ['Temperature','Pressure','delV','delG','LogK']
name = input('Input the name of the CSV file')
finalName = name + ".csv"
df.to_csv(finalName, index = False)
def options(self):
print('Welcome to DEWPython, here are the options you can run:')
print('1. DEW(): this initializes a Deep Earth Water Model Object')
print(' -The DEW object requires the set_inputs, set_outputs, set_TPRho, and calculate methods to be run.')
print(' -You can also utilize the import_custom_sheets method to import custom CSV data')
print(' -After calculating you can use the make_plots or export_to_csv methods.')
print('2. run_supcrt: this initializes an inline run of SUPCRTBL')
print(' -After initializing the SUPCRTBL object, run calculate_supcrt to store the supcrt outputs in arrays')
print(' -You can also use run_supcrt on a supcrt ouput file that has already been run by adding the optional argument of the file name')
print(' -After this you can run make_supcrt_plots to plot the supcrt files akin the a DEW file')
######################################
####### METHODS FOR SUPCRT ###########
######################################
def outLoop(self):
'''A helper function to allow SUPCRTBL to run'''
running = True
while(running):
line = self.pout.readline().decode(sys.stdout.encoding)
print(line, end='')
running='\n' in line
print('Finished')
def outLoop2(self):
'''A helper function to allow SUPCRT96 to run'''
running = True
while(running):
line = self.pout.readline().decode(sys.stdout.encoding)
running='\n' in line
def run_supcrt(self, version = '96'):
'''A function that runs the pre-compiled SUPCRTBL found in the file folder'''
if version != '96':
sup_path = '/'.join(('resources', 'SUPCRTBL.exe'))
supPath = pkg_resources.resource_filename(resource_package, sup_path)
else:
sup_path = '/'.join(('resources', 'supcrt96.exe'))
supPath = pkg_resources.resource_filename(resource_package, sup_path)
self.proc = subprocess.Popen(supPath,shell = True, stdout = subprocess.PIPE, stdin = subprocess.PIPE, stderr = subprocess.STDOUT)
self.pout = self.proc.stdout
self.pin = self.proc.stdin
threading.Thread(target=self.outLoop).start()
while(self.proc.poll() is None):
var = input('User Input: ')
if '.txt' in var:
self.supcrtFile = op.dirname(op.abspath(__file__)) + '\\resources\\' + var
inp=bytearray(var +'\n', sys.stdin.encoding)
if(self.proc.poll() is None):
self.pin.write(inp)
self.pin.flush()
return
def calculate_supcrt_special(self, customFile = None):
'''Calculates the output from either SUPCRTBL/SUPCRT96 at isothermal/isobaric temperatures'''
returnLst = {}
if customFile != None:
filename = op.dirname(op.abspath(os.getcwd()))+ '\\' + customFile
elif len(self.supcrtFile) ==0:
raise ValueError("You haven't run SUPCRT yet")
else:
filename = self.supcrtFile
with open(filename, 'r') as f:
impor = f.read()
import_data = impor.replace('\t', ' ')
split = import_data.split('\n')
for i in range(len(split)):
try:
if 'ISOTHERMS(degC)' in split[i]:
finalTemp = " ".join(split[i].split()).split(' ')[5]
finalPress = " ".join(split[i+1].split()).split(' ')[6]
returnVar = input('Enter reaction title')
except:
continue
if 'STANDARD STATE PROPERTIES OF THE REACTION AT ELEVATED TEMPERATURES AND PRESSURES' in split[i]:
subLst = []
temp = []
pres = []
DH2 = []
lgK = []
dlG = []
dlH = []
dlS = []
dlV = []
dlCp = []
subDict = {}
for item in split[(i+4):]:
if len(item) > 0:
subLst = (" ".join(item.split())).split(' ')
try:
float(subLst[0])
except:
continue
try:
a = subLst[0]
b = subLst[1]
c = subLst[2]
d = subLst[3]
e = subLst[4]
f = subLst[5]
g = subLst[6]
h = subLst[7]
i = subLst[8]
temp.append(a)
pres.append(b)
DH2.append(c)
lgK.append(d)
dlG.append(e)
dlH.append(f)
dlS.append(g)
dlV.append(h)
dlCp.append(i)
if float(subLst[0]) == finalTemp and float(subLst[1]) == finalPress:
break
except:
continue
subDict['Temperature'] = [float(i) for i in temp]
subDict['Pressure'] = [float(i) for i in pres]
DH2Lst = []
lgKLst = []
dlGLst = []
dlHLst = []
dlSLst = []
dlVLst = []
dlCpLst = []
for i in range(len(DH2)):
try:
DH2Lst.append(float(DH2[i]))
except:
DH2Lst.append(0)
try:
lgKLst.append(float(lgK[i]))
except:
lgKLst.append(0)
try:
dlGLst.append(float(dlG[i]))
except:
dlGLst.append(0)
try:
dlHLst.append(float(dlH[i]))
except:
dlHLst.append(0)
try:
dlSLst.append(float(dlS[i]))
except:
dlSLst.append(0)
try:
dlVLst.append(float(dlV[i]))
except:
dlVLst.append(0)
try:
dlCpLst.append(dlCp[i])
except:
dlCpLst.append[0]
subDict['DH2O'] = DH2Lst
subDict['LogK'] = lgKLst
subDict['delG'] = dlGLst
subDict['delH'] = dlHLst
subDict['delS'] = dlSLst
subDict['delV'] = dlVLst
subDict['delCp'] = dlCpLst
returnLst[returnVar] = subDict
self.supcrtOut = returnLst
def supcrt_inp(self, rxn_lst, title, reaction_type = 'psat'):
'''Takes a list of reaction lists (comprised of tuples) and runs supcrt'''
for reaction in rxn_lst:
sup_path = '/'.join(('resources', 'supcrt96.exe'))
supPath = pkg_resources.resource_filename(resource_package, sup_path)
self.proc = subprocess.Popen(supPath,stdout=subprocess.PIPE, stdin=subprocess.PIPE,stderr=subprocess.STDOUT, shell=True)
self.pout = self.proc.stdout
self.pin = self.proc.stdin
it = 0
rxnVar = 'realReac.con'
if reaction_type != 'psat':
rxnVar = 'Xtend.con'
if len(title) < 1:
title = input('What is the title of your reaction?')
comm = ['n', 'updateSlop1.dat', '2', rxnVar, '2', '1', title]
for component in reaction:
if component[1] not in nameLst:
print(str(component[1]) + ' is not in the slop16 database. Please check your spelling and try again. You can use the search function the query the database.')
else:
comm.append(str(component[0]) + ' ' + component[1])
comm.append('0')
comm.append('y')
comm.append('n')
comm.append(title + '.txt')
comm.append('1')
comm.append('1')
comm.append('empty')
threading.Thread(target=self.outLoop2).start()
while(self.proc.poll() is None):
try:
inp = comm[it]
it += 1
# inp = bytearray(input('User Input: ')+'\n',sys.stdin.encoding)
if(self.proc.poll() is None):
self.pin.write(bytearray(inp+'\n',sys.stdin.encoding))
self.pin.flush()
except:
pass
return
def calculate_supcrt(self, customFile = None):
'''Calculates an output of thermodynamic properties from a SUPCRTBL output file in the same directory. User must input
stopping temperature and pressure to allow the program to calculate properly.
'''
returnLst = {}
max_temp = input('Input the Maximum Temperature')
max_press = input('Input the Maximum Pressure')
max_temp = float(max_temp)
max_press = float(max_press)
if customFile != None:
file_Path = op.dirname(op.abspath(os.getcwd()))+ '\\' + customFile
elif len(self.supcrtFile) ==0:
raise ValueError("You haven't run SUPCRT yet")
else:
filename = self.supcrtFile
filePath='/'.join(('resources', filename))
file_Path = pkg_resources.resource_filename(resource_package, filepath)
with open(file_Path, 'r') as f:
impor = f.read()
import_data = impor.replace('\t', ' ')
split = import_data.split('\n')
for i in range(len(split)):
try:
if 'REACTION TITLE' in split[i]:
returnVar = " ".join(split[i+1].split()).split(' ')[0]
elif '************************************ REACTION' in split[i]:
returnVar = " ".join(split[i+4].split()).split(' ')[0]
except:
continue
if 'STANDARD STATE PROPERTIES OF THE REACTION AT ELEVATED TEMPERATURES AND PRESSURES' in split[i]:
subLst = []
temp = []
pres = []
DH2 = []
lgK = []
dlG = []
dlH = []
dlS = []
dlV = []
dlCp = []
subDict = {}
for item in split[(i+7):]:
try:
if len(item) > 0:
subLst = (" ".join(item.split())).split(' ')
temp.append(subLst[0])
pres.append(subLst[1])
DH2.append(subLst[2])
lgK.append(subLst[3])
dlG.append(subLst[4])
dlH.append(subLst[5])
dlS.append(subLst[6])
dlV.append(subLst[7])
dlCp.append(subLst[8])
if float(subLst[0]) == max_temp and float(subLst[1]) == max_press:
break
except:
continue
subDict['Temperature'] = [float(i) for i in temp]
subDict['Pressure'] = [float(i) for i in pres]
subDict['DH2O'] = [float(i) for i in DH2]
subDict['LogK'] = [float(i) for i in lgK]
subDict['delG'] = [float(i) for i in dlG]
subDict['delH'] = [float(i) for i in dlH]
subDict['delS'] = [float(i) for i in dlS]
storeLst = []
for i in dlV:
if i =='*********' or i =='NaN':
storeLst.append(0)
else:
storeLst.append(i)
subDict['delV'] = storeLst
subDict['delCp'] = [float(i) for i in dlCp]
returnLst[returnVar] = subDict
self.supcrtOut = returnLst
def make_supcrt_plots(self):
'''Creates plots of LogK and delV for already-calculated SUPCRTBL functions. Produces the same set of plots as the DEW produces'''
for i in self.supcrtOut:
plt.figure()
plt.plot(self.supcrtOut[i]['Temperature'], self.supcrtOut[i]['LogK'])
plt.title('LogK vs. Temp for ' + i)
plt.xlabel('Temp, Deg C')
plt.ylabel('LogK')
plt.show()
plt.figure()
plt.plot(self.supcrtOut[i]['Pressure'], self.supcrtOut[i]['LogK'])
plt.title('LogK vs. Pressure for ' + i)
plt.ylabel('LogK')
plt.xlabel('Pressure (Kb)')
plt.show()
for i in self.supcrtOut:
plt.figure()
plt.plot(self.supcrtOut[i]['Temperature'], self.supcrtOut[i]['delG'])
plt.title('delV vs. Temp for ' + i)
plt.xlabel('Temp, Deg C')
plt.ylabel('delG')
plt.show()
plt.figure()
plt.plot(self.supcrtOut[i]['Pressure'], self.supcrtOut[i]['delG'])
plt.title('delV vs. Pressure for ' + i)
plt.ylabel('delG')
plt.xlabel('Pressure (Kb)')
plt.show()
for i in self.supcrtOut:
plt.figure()
plt.plot(self.supcrtOut[i]['Temperature'], self.supcrtOut[i]['delV'])
plt.title('delV vs. Temp for ' + i)
plt.xlabel('Temp, Deg C')
plt.ylabel('delV')
plt.show()
plt.figure()
plt.plot(self.supcrtOut[i]['Pressure'], self.supcrtOut[i]['delV'])
plt.title('delV vs. Temp for ' + i)
plt.ylabel('delV')
plt.xlabel('Pressure (Kb)')
plt.show()
class DEWEquations:
'''The class here imports all the equations that the authors of the Deep Earth Water Model Excel Sheet use
and converts them into Python'''
def calculateDensity(pressure, temperature, equation, error, Psat):
''' Function to calculate the density of water. Essentially performs guesses and checks with
different densities until it reaches the correct pressure down to two decimal places,
as calculated by either Zhang & Duan (2005) or Zhang & Duan (2009).
---Input---
pressure - The pressure to calculate the density of water at, in bars
temperature - The temperature to calculate the density of water at, in Celsius
equation - Determines which equation of state to use in calculating the density.
equation = 1 corresponds to using Zhang & Duan (2005)
equation = 2 corresponds to using Zhang & Duan (2009)
error - This function uses a form of the bisection method. This variable indicates
how close the approximation should get. Eg. if error = 0.01, the density calculated
will calculate the pressure using the respective equation accurate to 0.01 of the input pressure
Psat - Determines if the polynomial fit to psat densities should be used in the event
that calculations are along the Psat curve
---Output---
Returns the density of water at the input pressure and temperature, in units of g/cm^3. The density returned
will calculate a pressure which differs from the input pressure by the value of "error" or less. If a proper value
for the equation was not entered, zero is returned.
'''
fn_return_value = 0
if Psat == True:
#This equation models the density of water as a function of temperature along the Psat curve.
#It has an R^2 value of 0.9999976885 as compared with Supcrt92 values.
fn_return_value = - 1.01023381581205E-104 * pow(temperature, np.double(40)) + - 1.1368599785953E-27 * pow(temperature, np.double(10)) + - 2.11689207168779E-11 * pow(temperature, np.double(4)) + 1.26878850169523E-08 * pow(temperature, np.double(3)) + - 4.92010672693621E-06 * pow(temperature, np.double(2)) + - 3.2666598612692E-05 * temperature + 1.00046144613017
else:
#Define variables
minGuess = 0.00001
guess = 0.00001
maxGuess = 7.5 * equation - 5
calcP = 0
#Loop through and find the density
for i in range(1, 51):
#Calculates the pressure using the specified equation
calcP = DEWEquations.calculatePressure(guess, temperature, equation)
#If the calculated pressure is not equal to input pressure, this determines a new
#guess for the density based on current guess and how the calculated pressure
#relates to the input pressure. In effect, this a form of a bisection method.
if np.absolute(calcP - pressure) > error:
if calcP > pressure:
maxGuess = guess
guess = ( guess + minGuess ) / 2
elif calcP < pressure:
minGuess = guess
guess = ( guess + maxGuess ) / 2
else:
fn_return_value = guess
break
return fn_return_value
def calculatePressure(density, temperature, equation):
'''Calculates the pressure of water as a function of density and temperature using one of two
equation of states.
---Input---
density - The density to use in finding a pressure, in g/cm^3
temperature - The temperature to use in finding a pressure, in Celsius
equation - The equation of state to use when calculating the pressure.
equation = 1 corresponds to using Zhang & Duan (2005)
equation = 2 corresponds to using Zhang & Duan (2009)
---Output---
Returns the pressure of water corresponding to the input density and temperature, in units of bars.
If a proper value for the equation was not entered, zero is returned.
'''
B = None
C = None
D = None
E = None
f = None
g = None
m = None
m = np.double(18.01528)
select_variable_0 = equation
if (select_variable_0 == 1):
ZD05_R = 83.144
ZD05_Vc = 55.9480373
ZD05_Tc = 647.25
TK = temperature + 273.15
Vr = m / density / ZD05_Vc
Tr = TK / ZD05_Tc
B = 0.349824207 - 2.91046273 / ( Tr * Tr ) + 2.00914688 / ( Tr * Tr * Tr )
C = 0.112819964 + 0.748997714 / ( Tr * Tr ) - 0.87320704 / ( Tr * Tr * Tr )
D = 0.0170609505 - 0.0146355822 / ( Tr * Tr ) + 0.0579768283 / ( Tr * Tr * Tr )
E = - 0.000841246372 + 0.00495186474 / ( Tr * Tr ) - 0.00916248538 / ( Tr * Tr * Tr )
f = - 0.100358152 / Tr
g = np.double(- 0.00182674744 * Tr)
delta = 1 + B / Vr + C / ( Vr * Vr ) + D / pow(Vr, np.double(4)) + E / pow(Vr, np.double(5)) + ( f / ( Vr * Vr ) + g / pow(Vr, np.double(4)) ) * np.exp(- 0.0105999998 / ( Vr * Vr ))
fn_return_value = ZD05_R * TK * density * delta / m
elif (select_variable_0 == 2):
ZD09_R = 0.083145
#Constant equal to ZD09_epsilon / (3.0626 * ZD09_omega^3)
ZD09_c1 = 6.971118009
#ZD09_epsilon = 510 'Lenard-Jones parameter in units of K
#ZD09_omega = 2.88 'Lenard-Jones parameter in units of 1E-10 m
#Prefactor calculated from 1000 * pow(ZD09_omega / 3.691, 3)
dm = 475.05656886 * density
#Prefactor calculated from 0.001 * pow(3.691 / ZD09_omega, 3)
Vm = 0.0021050125 * ( m / density )
#Prefactor calculated from 154 / ZD09_epsilon
Tm = 0.3019607843 * ( temperature + 273.15 )
B = 0.029517729893 - 6337.56452413 / ( Tm * Tm ) - 275265.428882 / ( Tm * Tm * Tm )
C = 0.00129128089283 - 145.797416153 / ( Tm * Tm ) + 76593.8947237 / ( Tm * Tm * Tm )
D = 2.58661493537E-06 + 0.52126532146 / ( Tm * Tm ) - 139.839523753 / ( Tm * Tm * Tm )
E = - 2.36335007175E-08 + 0.00535026383543 / ( Tm * Tm ) - 0.27110649951 / ( Tm * Tm * Tm )
f = 25038.7836486 / ( Tm * Tm * Tm )
delta = 1 + B / Vm + C / ( Vm * Vm ) + D / pow(Vm, 4) + E / pow(Vm, 5) + f / ( Vm * Vm ) * ( 0.73226726041 + 0.015483335997 / ( Vm * Vm ) ) * np.exp(- 0.015483335997 / ( Vm * Vm ))
Pm = ZD09_R * Tm * delta / Vm
fn_return_value = Pm * ZD09_c1
else:
fn_return_value = 0
return fn_return_value
def calculate_drhodP(density, temperature, equation):
'''Calculates the partial derivative of density with respect to pressure, i.e. (d(rho)/dP)_T
This is done using one of two equations of state for water.
---Input---
density - The density of water, in g/cm^3
temperature - The temperature of water, in Celsius
equation - The equation of state to use when calculating the pressure.
equation = 1 corresponds to using Zhang & Duan (2005)
equation = 2 corresponds to using Zhang & Duan (2009)
---Output---
Returns the partial derivative of density with respect to pressure of water corresponding
to the input density and temperature, in units of g^3/cm^3/bar. If a proper value for the equation
was not entered, zero is returned.
'''
B = None
C = None
D = None
E = None
f = None
g = None
m = None
m = np.double(18.01528)
select_variable_1 = equation
if (select_variable_1 == 1):
ZD05_R = 83.144
ZD05_Vc = 55.9480373
ZD05_Tc = 647.25
TK = np.double(temperature + 273.15)
Tr = TK / ZD05_Tc
cc = ZD05_Vc / m
Vr = m / ( density * ZD05_Vc )
B = 0.349824207 - 2.91046273 / ( Tr * Tr ) + 2.00914688 / ( Tr * Tr * Tr )
C = 0.112819964 + 0.748997714 / ( Tr * Tr ) - 0.87320704 / ( Tr * Tr * Tr )
D = 0.0170609505 - 0.0146355822 / ( Tr * Tr ) + 0.0579768283 / ( Tr * Tr * Tr )
E = - 0.000841246372 + 0.00495186474 / ( Tr * Tr ) - 0.00916248538 / ( Tr * Tr * Tr )
f = - 0.100358152 / Tr
#####
# This value has been edited to be consistent with Mark Ghiorso's objective-C version of DEW and the original Zhang and Duan 2005 paper,
# although it is incosistent with the Excel-implemented DEW Model
g = np.double(- 0.00182674744 * Tr)
########
delta = 1 + B / Vr + C / ( Vr * Vr ) + D / pow(Vr, 4) + E / pow(Vr, 5) + ( f / ( Vr * Vr ) + g / pow(Vr, 4) ) * np.exp(- 0.0105999998 / pow(Vr, 2))
kappa = B * cc + 2 * C * ( cc * cc ) * density + 4 * D * pow(cc, 4) * pow(density, 3) + 5 * E * pow(cc, 5) * pow(density, 4) + ( 2 * f * ( cc * cc ) * density + 4 * g * pow(cc, 4) * pow(density, 3) - ( f / ( Vr * Vr ) + g / pow(Vr, 4) ) * ( 2 * 0.0105999998 * ( cc * cc ) * density ) ) * np.exp(- 0.0105999998 / ( Vr * Vr ))
fn_return_value = m / ( ZD05_R * TK * ( delta + density * kappa ) )
elif (select_variable_1 == 2):
ZD09_R = 0.083145
ZD09_c1 = 6.971118009
#ZD09_epsilon = 510 'Lenard-Jones parameter in units of K
#ZD09_omega = 2.88 'Lenard-Jones parameter in units of 1E-10 m
#Prefactor calculated from 1000 * pow(ZD09_omega / 3.691, 3)
dm = 475.05656886 * density
#Prefactor calculated from 0.001 * pow(3.691 / ZD09_omega, 3)
Vm = 0.0021050125 * ( m / density )
#Prefactor calculated from 154 / ZD09_epsilon
Tm = 0.3019607843 * ( temperature + 273.15 )
B = 0.029517729893 - 6337.56452413 / ( Tm * Tm ) - 275265.428882 / ( Tm * Tm * Tm )
C = 0.00129128089283 - 145.797416153 / ( Tm * Tm ) + 76593.8947237 / ( Tm * Tm * Tm )
D = 2.58661493537E-06 + 0.52126532146 / ( Tm * Tm ) - 139.839523753 / ( Tm * Tm * Tm )
E = - 2.36335007175E-08 + 0.00535026383543 / ( Tm * Tm ) - 0.27110649951 / ( Tm * Tm * Tm )
f = 25038.7836486 / ( Tm * Tm * Tm )
delta = 1 + B / Vm + C / ( Vm * Vm ) + D / pow(Vm, 4) + E / pow(Vm, 5) + f / ( Vm * Vm ) * ( 0.73226726041 + 0.015483335997 / ( Vm * Vm ) ) * np.exp(- 0.015483335997 / ( Vm * Vm ))
kappa = B / m + 2 * C * dm / ( m * m ) + 4 * D * pow(dm, 3) / pow(m, 4) + 5 * E * pow(dm, 4) / pow(m, 5) + ( 2 * f * dm / ( m * m ) * ( 0.73226726041 + 0.015483335997 / ( Vm * Vm ) ) + f / pow(Vm, 2) * ( 1 - 0.73226726041 - 0.015483335997 / ( Vm * Vm ) ) * ( 2 * 0.015483335997 * dm / ( m * m ) ) ) * np.exp(- 0.015483335997 / ( Vm * Vm ))
##### Adding a comment here because I've made ZD09_c4 into ZD09 C_1 #######
##### Original line######
#fn_return_value = ZD09_c1 * m / ( ZD09_c4 * ZD09_R * Tm * ( delta + dm * kappa ) )
fn_return_value = ZD09_c1 * m / ( ZD09_c1 * ZD09_R * Tm * ( delta + dm * kappa ) )
else:
fn_return_value = 0
return fn_return_value
def calculateGibbsOfWater(pressure, temp, equation, densityEquation, Psat):
'''This function calculates the Gibbs Free Energy of Water. It can calculate with two equations.
---Input---'
pressure - The pressure to calculate the Gibbs Free Energy at, in bars
temperature - The temperature to calculate the Gibbs Free Energy at, in Celsius
equation - Determines which equation to use to calculate the Gibbs Free Energy,
either Delaney & Helgeson (1978), corresonding to equation = 1, or simply integrating
over the volume of water, corresponding to equation = 2
density Equation - Determines which equation to use to find the density, and thus the volume of water.
Psat - Determines if the calculation should be done at Psat.
---Output---
Returns the Gibbs Free Energy of water in units of cal/mol. If a proper value for equation was not entered,
zero is returned.
'''
if Psat == True:
#This equation models the Gibbs Free Energy of water as a function of temperature along the Psat curve.
#It has an R^2 value of 0.9999999984518 as compared with Supcrt92 values.
fn_return_value = - 2.72980941772081E-103 * pow(temp, np.double(40)) + 2.88918186300446E-25 * pow(temp, np.double(10)) + - 2.21891314234246E-08 * pow(temp, np.double(4)) + 3.0912103873633E-05 * pow(temp, np.double(3)) + - 3.20873264480928E-02 * pow(temp, np.double(2)) + - 15.169458452209 * temp + - 56289.0379433809
else:
select_variable_2 = equation
if (select_variable_2 == 1):
coeff = {}
coeff[0] = - 56130.073
coeff[1] = 0.38101798
coeff[2] = - 0.0000021167697
coeff[3] = 2.0266445E-11
coeff[4] = - 8.3225572E-17
coeff[5] = - 15.285559
coeff[6] = 0.0001375239
coeff[7] = - 1.5586868E-09
coeff[8] = 6.6329577E-15
coeff[9] = - 0.026092451
coeff[10] = 0.000000035988857
coeff[11] = - 2.7916588E-14
coeff[12] = 0.000017140501
coeff[13] = - 1.6860893E-11
coeff[14] = - 6.0126987E-09
gibbsFreeEnergy = 0
Count = 0
for j in range(0, 5):
for k in range(0, 5 - j):
temp = np.absolute(temp)
gibbsFreeEnergy = gibbsFreeEnergy + coeff[Count] * pow((temp), np.double(j)) * pow(pressure, np.double(k))
Count = Count + 1
fn_return_value = gibbsFreeEnergy
elif (select_variable_2 == 2):
#then defines the gibbs free energy as the integral over the volume as a function of temperature.
#We can only perform this calculation if we can use one of the two density equations included
#in the code. If densityEquation equals three, then that implies the user chose to use custom
#density values. Because this procedure requires integration over a range of densities, this
#cannot be calculated if the user has custom density values. Therefore, this will just return zero.
if ( densityEquation == 3 ) :
fn_return_value = 0
#Gibbs Free Energy of water at 1 kb. This equation is a polynomial fit to data as a function of temperature.
#It is valid in the range of 100 to 1000 C.
temp = np.absolute(temp)
GAtOneKb = 2.6880734E-09 *(temp * temp)*(temp*temp) + 0.00000063163061 * (temp * temp * temp) - 0.019372355 * ( temp * temp ) - 16.945093 * temp - 55769.287
if pressure < 1000:
fn_return_value = 0
elif pressure == 1000:
fn_return_value = GAtOneKb
elif pressure > 1000:
integral = 0
#Integral is sum of rectangles with this width. This function in effect limits the spacing
#to 20 bars so that very small pressures do not have unreasonably small widths. Otherwise the width
#is chosen such that there are always 500 steps in the numerical integration. This ensures that for very
#high pressures, there are not a huge number of steps calculated which is very computationally taxing.
if ( pressure - 1000 ) / 500 < 20:
spacing = 20
else:
spacing = ( pressure - 1000 ) / 500
for i in range(1000, pressure + 1, int(spacing)):
#This integral determines the density only down to an error of 100 bars
#rather than the standard of 0.01. This is done to save computational
#time. Tests indicate this reduces the computation by about a half while
#introducing little error from the standard of 0.01.
integral = integral + ( 18.01528 / DEWEquations.calculateDensity(i, temp, densityEquation, 100, False) / 41.84 ) * spacing
fn_return_value = GAtOneKb + integral
else:
fn_return_value = 0
return fn_return_value
def calculateEpsilon(density, temperature, equation, Psat):
''' This function calculates the dielectric constant (epsilon) of water using one of four possible equations.
---Input---
density - The density of water to use in calculating epsilon, in g/cm^3
temperature - The temperature to calculate epsilon with, in Celsius
equation - Determines which equation should be used to calculate the dielectric constant of water.
equation = 1 corresponds to using Johnson & Norton (1991), the equation used in Supcrt
equation = 2 corresponds to using Franck (1990)
equation = 3 corresponds to using Fernandez (1997)
equation = 4 corredponds to using the Power Function. This is an equation derived by
Dimitri Sverjensky and Brandon Harison at Johns Hopkins University.
Psat - Determines if the polynomial fit to psat dielectric constant values should be used
in the event that calculations are along the Psat curve
---Output---
Returns the Dielectric constant of water at the given density and temperature. If a proper value
for equation was not entered, zero is returned.
'''
if Psat == True:
#This equation models the dielectric constant of water as a function of temperature along the Psat curve.
#It has an R^2 value of 0.9999991719 as compared with Supcrt92 values.
fn_return_value = - 1.66686763214295E-77 * pow(temperature, np.double(30)) + - 9.02887020379887E-07 * pow(temperature, np.double(3)) + 8.4590281449009E-04 * pow(temperature, np.double(2)) + - 0.396542037778945 * temperature + 87.605024245432
else:
select_variable_3 = equation
if (select_variable_3 == 1):
T_hat = ( temperature + 273.15 ) / 298.15
k0 = 1
k1 = 14.70333593 / T_hat
k2 = 212.8462733 / T_hat - 115.4445173 + 19.55210915 * T_hat
k3 = - 83.3034798 / T_hat + 32.13240048 * T_hat - 6.69409865 * ( T_hat * T_hat )
k4 = - 37.86202045 / ( T_hat * T_hat ) + 68.87359646 / T_hat - 27.29401652
fn_return_value = k0 + k1 * density + k2 * ( density * density ) + k3 * pow(density, 3) + k4 * pow(density, 4)
elif (select_variable_3 == 2):
pi = 3.14159265358979
omega = 0.0000000268
k = 1.380648E-16
Na = 6.022E+23
mu = 2.33E-18
rhostar = ( density * 0.055508 ) * pow(omega, 3) * Na
mustarsq = pow(mu, 2) / ( k * ( temperature + 273.15 ) * pow(omega, 3) )
y = ( 4 * pi / 9 ) * rhostar * mustarsq
f1 = 0.4341 * pow(rhostar, 2)
f2 = - ( 0.05 + 0.75 * pow(rhostar, 3) )
f3 = - 0.026 * pow(rhostar, 2) + 0.173 * pow(rhostar, 4)
fn_return_value = ( ( 3 * y ) / ( 1 - f1 * y ) ) * ( 1 + ( 1 - f1 ) * y + f2 * ( y * y ) + f3 * ( y * y * y ) ) + 1
elif (select_variable_3 == 3):
#Values for N_k
N_k = {}
N_k[0] = 0.978224486826
N_k[1] = - 0.957771379375
N_k[2] = 0.237511794148
N_k[3] = 0.714692224396
N_k[4] = - 0.298217036956
N_k[5] = - 0.108863472196
N_k[6] = 0.0949327488264
N_k[7] = - 0.00980469816509
N_k[8] = 0.000016516763497
N_k[9] = 9.37359795772E-05
N_k[10] = - 1.2317921872E-10
N_k[11] = 0.00196096504426
#Values for i_k
i_k = {}
i_k[0] = 1
i_k[1] = 1
i_k[2] = 1
i_k[3] = 2
i_k[4] = 3
i_k[5] = 3
i_k[6] = 4
i_k[7] = 5
i_k[8] = 6
i_k[9] = 7
i_k[10] = 10
#Values for j_k
j_k = {}
j_k[0] = 0.25
j_k[1] = 1
j_k[2] = 2.5
j_k[3] = 1.5
j_k[4] = 1.5
j_k[5] = 2.5
j_k[6] = 2
j_k[7] = 2
j_k[8] = 5
j_k[9] = 0.5
j_k[10] = 10
avogadro = 6.0221367E+23
dipole = 6.138E-30
epsilon_o = 8.8541878176204E-12
boltzmann = 1.380658E-23
alpha = 1.636E-40
density_c = 17873.728
T_c = 647.096
#Convert density and temperature units
density_molm3 = density * 0.055508 * 1000000
T_K = temperature + 273.15
#Defining the g equation
g = 1
for ii in range(0, 11):
g = g + N_k[ii] * pow(density_molm3 / density_c, np.double(i_k[ii])) * pow(T_c / T_K, np.double(j_k[ii]))
g = g + N_k[11] * ( density_molm3 / density_c ) * pow(T_K / 228 - 1, - 1.2)
#Defining the A, B, and C equations
A = ( avogadro * pow(dipole, 2) * density_molm3 * g ) / ( epsilon_o * boltzmann * T_K )
B = ( avogadro * alpha * density_molm3 ) / ( 3 * epsilon_o )
C = 9 + 2 * A + 18 * B + A * A + 10 * A * B + 9 * B * B
fn_return_value = ( 1 + A + 5 * B + np.sqrt(C) ) / ( 4 - 4 * B )
elif (select_variable_3 == 4):
#Relevant parameters
a1 = - 1.57637700752506E-03
a2 = 6.81028783422197E-02
a3 = 0.754875480393944
b1 = - 8.01665106535394E-05
b2 = - 6.87161761831994E-02
b3 = 4.74797272182151
A = a1 * temperature + a2 * np.sqrt(temperature) + a3
B = b1 * temperature + b2 * np.sqrt(temperature) + b3
fn_return_value = np.exp(B) * pow(density, np.double(A))
else:
fn_return_value = 0
return fn_return_value
def calculate_depsdrho(density, temperature, equation):
'''Calculates the partial derivative of the dielectric constant (epsilon) with respect to density, i.e. (d(eps)/d(rho))_T
This is done using one of four possible equations
---Input---
density - The density of water to calculate with, in g/cm^3
temperature - The temperature to calculate with, in Celsius
equation - Determines which equation should be used to calculate the derivative
equation = 1 corresponds to using Johnson & Norton (1991), the equation used in Supcrt
equation = 2 corresponds to using Franck (1990)
equation = 3 corresponds to using Fernandez (1997)
equation = 4 corredponds to using the Power Function. This is an equation derived by
Dimitri Sverjensky and Brandon Harison at Johns Hopkins University.
---Output---
Returns the partial derivative of the dielectric constant with respect to density in units of cm^3/g. If a proper value
for equation was not entered, zero is returned.
'''
select_variable_4 = equation
if (select_variable_4 == 1):
T_hat = ( temperature + 273.15 ) / 298.15
k1 = 14.70333593 / T_hat
k2 = 212.8462733 / T_hat - 115.4445173 + 19.55210915 * T_hat
k3 = - 83.3034798 / T_hat + 32.13240048 * T_hat - 6.69409865 * ( T_hat * T_hat )
k4 = - 37.86202045 / ( T_hat * T_hat ) + 68.87359646 / T_hat - 27.29401652
fn_return_value = k1 + 2 * k2 * density + 3 * k3 * pow(density, 2) + 4 * k4 * pow(density, 3)
elif (select_variable_4 == 2):
pi = 3.14159265358979
omega = 0.0000000268
k = 1.380648E-16
Na = 6.022E+23
mu = 2.33E-18
density = density * 0.055508
cc = pow(omega, 3) * Na
rhostar = density * cc
mustarsq = pow(mu, 2) / ( k * ( temperature + 273.15 ) * pow(omega, 3) )
y = ( 4 * pi / 9 ) * rhostar * mustarsq
f1 = 0.4341 * pow(rhostar, 2)
f2 = - ( 0.05 + 0.75 * pow(rhostar, 3) )
f3 = - 0.026 * pow(rhostar, 2) + 0.173 * pow(rhostar, 4)
dydrho = ( 4 * pi / 9 ) * mustarsq * cc
df1drho = 2 * 0.4341 * pow(cc, 2) * density
df2drho = - 3 * 0.75 * pow(cc, 3) * pow(density, 2)
df3drho = - 2 * 0.026 * pow(cc, 2) * density + 4 * 0.173 * pow(cc, 4) * pow(density, 3)
eps = ( ( 3 * y ) / ( 1 - f1 * y ) ) * ( 1 + ( 1 - f1 ) * y + f2 * ( y * y ) + f3 * ( y * y * y ) ) + 1
#The 0.055508 value converts the units from cm^3/mol to cm^3/g
fn_return_value = 0.05508 * ( ( ( dydrho + pow(y, 2) * df1drho ) / ( 1 - f1 * y ) ) * ( eps - 1 ) / y + ( ( 3 * y ) / ( 1 - f1 * y ) ) *
( - df1drho * y + df2drho * pow(y, 2) + df3drho * pow(y, 3) + ( 1 - f1 + 2 * f2 * y + 3 * f3 * y * y ) * dydrho ) )
elif (select_variable_4 == 3):
#Values for N_k
N_k = {}
N_k[0] = 0.978224486826
N_k[1] = - 0.957771379375
N_k[2] = 0.237511794148
N_k[3] = 0.714692224396
N_k[4] = - 0.298217036956
N_k[5] = - 0.108863472196
N_k[6] = 0.0949327488264
N_k[7] = - 0.00980469816509
N_k[8] = 0.000016516763497
N_k[9] = 9.37359795772E-05
N_k[10] = - 1.2317921872E-10
N_k[11] = 0.00196096504426
#Values for i_k
i_k = {}
i_k[0] = 1
i_k[1] = 1
i_k[2] = 1
i_k[3] = 2
i_k[4] = 3
i_k[5] = 3
i_k[6] = 4
i_k[7] = 5
i_k[8] = 6
i_k[9] = 7
i_k[10] = 10
#Values for j_k
j_k = {}
j_k[0] = 0.25
j_k[1] = 1
j_k[2] = 2.5
j_k[3] = 1.5
j_k[4] = 1.5
j_k[5] = 2.5
j_k[6] = 2
j_k[7] = 2
j_k[8] = 5
j_k[9] = 0.5
j_k[10] = 10
avogadro = 6.0221367E+23
dipole = 6.138E-30
epsilon_o = 8.8541878176204E-12
boltzmann = 1.380658E-23
alpha = 1.636E-40
density_c = 17873.728
T_c = 647.096
#Convert density and temperature units
density_molm3 = density * 0.055508 * 1000000
T_K = temperature + 273.15
#Defining the g equation
g = 1
for ii in range(0, 11):
g = g + N_k[ii] * pow(density_molm3 / density_c, np.double(i_k[ii])) * pow(T_c / T_K, np.double(j_k[ii]))
g = g + N_k[11] * ( density_molm3 / density_c ) * pow(T_K / 228 - 1, - 1.2)
#Defining the dgdrho equation
dgdrho = 0
for ii in range(0, 11):
dgdrho = dgdrho + i_k[ii] * N_k[ii] * ( pow(density_molm3, np.double(i_k[ii] - 1)) / pow(density_c, np.double(i_k[ii])) ) * pow(T_c / T_K, np.double(j_k[ii]))
dgdrho = dgdrho + ( N_k[11] / density_c ) * pow(T_K / 228 - 1, - 1.2)
#Defining the A, B, and C equations
A = ( avogadro * pow(dipole, 2) * density_molm3 * g ) / ( epsilon_o * boltzmann * T_K )
B = ( avogadro * alpha * density_molm3 ) / ( 3 * epsilon_o )
C = 9 + 2 * A + 18 * B + A * A + 10 * A * B + 9 * B * B
#Defining the derivatives and epsilon
dAdrho = A / density_molm3 + ( A / g ) * dgdrho
dBdrho = B / density_molm3
dCdrho = 2 * dAdrho + 18 * dBdrho + 2 * A * dAdrho + 10 * ( dAdrho * B + A * dBdrho ) + 18 * B * dBdrho
eps = ( 1 + A + 5 * B + pow(np.double(C), 0.5)) / ( 4 - 4 * B )
#The 55508 value converts the units from m^3/mol to cm^3/g
fn_return_value = 55508 * ( 1 / ( 4 - 4 * B ) ) * ( 4 * dBdrho * eps + dAdrho + 5 * dBdrho + 0.5 * pow(np.double(C), - 0.5) * dCdrho )
elif (select_variable_4 == 4):
#Relevant parameters
a1 = - 1.57637700752506E-03
a2 = 6.81028783422197E-02
a3 = 0.754875480393944
b1 = - 8.01665106535394E-05
b2 = - 6.87161761831994E-02
b3 = 4.74797272182151
A = a1 * temperature + a2 * np.sqrt(temperature) + a3
B = b1 * temperature + b2 * np.sqrt(temperature) + b3
fn_return_value = A * np.exp(B) * pow(density, A - 1)
else:
fn_return_value = 0
return fn_return_value
def calculateOmega(P, T, density, name, wref, Z):
'''This function calculates the born coefficient omega for aqueous species as a function of pressure and temeprature
---Input---
P - Pressure to calculate at, in bars
T - Temperature to calculate at, in Celsius
density - Density of water to calculate omega at, in g/cm^3. This could be calculated from P and T, but
it is used as an input parameter to save on calculation time.
name - The name of the species this is being calculated for.
wref - The value of omega at standard pressure and temperature, in units of cal/mol. This should not be
the value generally given as omega*1E-5, but rather the actual value of omega.
Z - The charge of the species
---Output---
Returns the value of omega at the input P and T. If Z is zero, the wprtr value is used. The value returned is
in units of cal/mol and NOT multiplied by 10^-5.
'''
#If species is hydrogen, the species is neutral, or the pressure is above 6 kb,
#this equation is not necessary because omega is very close to wref.
if name == 'H+' or Z == 0 or P > 6000:
fn_return_value = wref
else:
#These equations are given by Shock et al. (1992)
eta = 166027
#Defines the electrostatic radius at reference pressure and temperature
reref = Z * Z / ( wref / eta + Z / 3.082 )
#This represents the pressure and temperature dependent solvent function
g = DEWEquations.calculateG(P, T, density)
#Defines the electrostatic radius at the input P and T
re = reref + np.abs(Z) * g
fn_return_value = eta * ( Z * Z / re - Z / ( 3.082 + g ) )
return fn_return_value
def calculateG(P, T, density):
'''Calculates the pressure and temperature dependent solvent function. This function should only be
used for pressures less than 6 kb.
---Input---
P - The pressure to calculate at, in bars
T - The temperature to calculate at, in celsius
density - The density of water at which to calculate g at, in g/cm^3
---Output---
Returns the value of the g function. If the density is greather than 1 g/cm^3, then zero is returned.'''
if density >= 1:
fn_return_value = 0
else:
a_g = - 2.037662 + 0.005747 * T - 0.000006557892 * T * T
b_g = 6.107361 - 0.01074377 * T + 0.00001268348 * T * T
#Calculates the difference function in the case where we need to calculate at Psat conditions
if ( P <= 1000 and T >= 155 and T <= 355 ) :
f = ( pow(( T - 155 ) / 300, 4.8) + 36.66666 * pow(( T - 155 ) / 300, np.double(16)) ) *( - 1.504956E-10 * pow(1000 - P, np.double(3)) + 5.017997E-14 * pow(1000 - P, np.double(4)) )
else:
f = 0
fn_return_value = a_g * pow(1 - density, b_g) - f
return fn_return_value
def calculate_domegadP(P, T, density, name, wref, Z, densityEquation, Psat):
'''This function calculates the derivative of the born coefficient omega with respect to pressure
for aqueous species as a function of pressure and temeprature
---Input---
P - Pressure to calculate at, in bars
T - Temperature to calculate at, in Celsius
density - Density of water to calculate omega at, in g/cm^3. This could be calculated from P and T, but
it is used as an input parameter to save on calculation time.
name - The name of the species this is being calculated for.
wref - The value of omega at standard pressure and temperature, in units of cal/mol. This should not be
the value generally given as omega*1E-5, but rather the actual value of omega.
Z - The charge of the species
densityEquation - Determines which equation to use in calculating the derivative of density
with respect to pressure. This is passed direction to calculate_dgdP
equation = 1 corresponds to Zhang & Duan (2005)
equation = 1 corresponds to Zhang & Duan (2009)
Psat - Determines if the calculation should be done along the Psat curve. In this case
there is no equation for drhodP and a polynomial fit to data from Shock et al. (1992) is used.
---Output---
Returns the value of the derivative of omega with respect to pressure at the input P and T. If Z is zero, then
the derivative is zero. The value returned is in units of cal/mol/bar
'''
#If species is hydrogen, the species is neutral, or the pressure is above 6 kb,
#this equation is not necessary because omega is very close to wref.
if name == 'H+' or Z == 0 or P > 6000:
fn_return_value = 0
else:
#These equations are given by Shock et al. (1992)
eta = 166027
#Defines the electrostatic radius at reference pressure and temperature
reref = Z * Z / ( wref / eta + Z / 3.082 )
#This represents the pressure and temperature dependent solvent function and its derivative
g = DEWEquations.calculateG(P, T, density)
dgdP = DEWEquations.calculate_dgdP(P, T, density, g, densityEquation, Psat)
#Defines the electrostatic radius at the input P and T
re = reref + np.absolute(Z) * g
fn_return_value = - eta * ( np.absolute(Z * Z * Z) / pow(re, 2) - Z / pow(3.082 + g, 2) ) * dgdP
return fn_return_value
def calculate_dgdP(P, T, density, g, equation, Psat = True):
'''Calculates the pressure derivative of the pressure and temperature dependent solvent function.
This function should only be used for pressures less than 6 kb.
---Input---
P - The pressure to calculate at, in bars
T - The temperature to calculate at, in celsius
density - The density of water at which to calculate g at, in g/cm^3
g - The value of the g solvent function at the input P and T
equation - Determines which equation to use in calculating the derivative of density
with respect to pressure
equation = 1 corresponds to Zhang & Duan (2005)
equation = 1 corresponds to Zhang & Duan (2009)
Psat - Determines if the calculation should be done along the Psat curve. In this case
there is no equation for drhodP and a polynomial fit to data from Shock et al. (1992) is used.
---Output---
Returns the pressure derivative of the g function. If the density is greather than 1 g/cm^3, then zero is returned.
'''
if Psat == True:
#This equation models the derivative of the g solvent function with respect to pressure and
#as a function of temperature along the Psat curve.
#It has an R^2 value of 0.99995027718 as compared with values listed in Shock et al. (1992).
#Particular care was taken to properly model the values at low temperatures which is why this
#function not simply a polynomial
if T < 0.01:
fn_return_value = 0
else:
fn_return_value = np.exp(1.37105493109451E-10 * pow(np.log(T), np.double(15)) + - 1.43605469318795E-06 * pow(np.log(T), np.double(10)) + 26.2649453651117 * np.log(T) + - 125.108856715714) * 0.000001
else:
if density >= 1:
fn_return_value = 0
else:
b_g = 6.107361 - 0.01074377 * T + 0.00001268348 * T * T
#Calculates the difference function in the case where we need to calculate at Psat conditions
if ( P <= 1000 and T >= 155 and T <= 355 ) :
dfdP = - ( pow(( T - 155 ) / 300, 4.8) + 36.66666 * pow(( T - 155 ) / 300, 16) ) * ( 3 * - 1.504956E-10 * pow(1000 - P, 2) + 4 * 5.017997E-14 * pow(1000 - P, 3) )
else:
dfdP = 0
fn_return_value = - b_g * DEWEquations.calculate_drhodP(density, T, equation) * g / ( 1 - density ) - dfdP
return fn_return_value
def calculateQ(pressure, temperature, density, densityEquation, epsilonEquation, Psat):
'''This method calculates the Born Coefficient Q as (1/eps^2)*(d(eps)/dP) - In other words the derivative of
epsilon with respect to pressure, divided by epsilon squared
---Input---
pressure - The pressure to calculate Q at, in bars
temperature - The temperature to calculate Q at, in Celsius
density - The density at the input pressure and temperature, input simply to save time, in g/cm^3
denistyEquation - The density equation to use in calculating the density of water.
epsilonEquation - The epsilon equation to use in calculating epsilon.
Psat - Determines if the calculation should be done at Psat.
---Output---
Outputs the value of Q in units of bar^-1
Calculates the pressure and temperature dependent solvent function. This function should only be
used for pressures less than 6 kb.
---Input---
P - The pressure to calculate at, in bars
T - The temperature to calculate at, in celsius
density - The density of water at which to calculate g at, in g/cm^3
---Output---
Returns the value of the g function. If the density is greather than 1 g/cm^3, then zero is returned.
'''
if Psat == True:
#This equation models the Q Born Coefficent as a function of temperature along the Psat curve.
#It has an R^2 value of 0.99999998602 as compared with values listed in Shock et al. (1992).
fn_return_value = ( 1.99258688758345E-49 * pow(temperature, np.double(20)) + - 4.43690270750774E-14 * pow(temperature, np.double(6)) + 4.29110215680165E-11 * pow(temperature, np.double(5)) + - 1.07146606081182E-08 * pow(temperature, np.double(4)) + 1.09982931856694E-06 * pow(temperature, np.double(3)) + 9.60705240954956E-06 * pow(temperature, np.double(2)) + 0.642579832259358 ) * 0.000001
else:
#This commented section is the code to calculate the value of Q using a finite difference derivative.
#-------------------------
# Dim epsilon, delta, epsilonPlusDelta As Double
#
# delta = 1
#
# epsilon = DEWEquations.calculateEpsilon(density, temperature, epsilonEquation, False)
#
# epsilonPlusDelta = DEWEquations.calculateEpsilon(calculateDensity(pressure + delta, temperature, densityEquation, 0.01, False), temperature, epsilonEquation, False)
#
# calculateQ = (1 / pow(np.double(epsilon), 2)) * ((epsilonPlusDelta - epsilon) / delta)
#-------------------------
eps = DEWEquations.calculateEpsilon(density, temperature, epsilonEquation, Psat)
depsdrho = DEWEquations.calculate_depsdrho(density, temperature, epsilonEquation)
drhodP = DEWEquations.calculate_drhodP(density, temperature, densityEquation)
fn_return_value = depsdrho * drhodP / ( eps * eps )
return fn_return_value
# In[9]:
# In[ ]:
Global variables
var Chi
-
X is the constant -3.090E-07 and has units of K^-2
var Conversion
-
A conversion factor present in DEW publications
var E_PrTr
-
Epsilon_{P_rT_r} is a unitless constant with value of 78.47
var Pr
-
The standard state pressure of 1 bar
var Psy
-
The value of this constant is 2600 bar
var T_r
-
The standard state temperature 298.15 with units K
var Theta
-
The value of this temperature is 228 Kelvin
var Upsilon
-
The value of this constant is -5.79865E-05 K^-1
var bigQ
-
Big Q is the 5.903E-07, and has units of bar^-1
var bigR
-
The gas constant with value 1.9858775 cal mol^-1 k^-1
Functions
def search(string)
-
A function to searh for species within DEWython
Expand source code
def search(string): '''A function to searh for species within DEWython''' for item in nameLst: if str.lower(string) in str.lower(item): print(item) for item in GasLst: if str.lower(string) in str.lower(item): print(item) for key in mineralDictionary: if str.lower(string) in str.lower(key): print(key)
Classes
class DEW
-
Expand source code
class DEW(object): def __init__(self): # User Option Parameters self.ptInput = 'Psat' '''The temperature and pressure input, options are Regular, Psat, or custom. Default is regular''' self.RhoOfWater = 'Z&D 2005' '''The density of water equation input, can be Zheng and Duan 2005, Zheng and Duan 2009, or custom. Default is Z&D 2005''' self.forceCustom = False '''The option to force custom Rho for P< 1 kb. Default is False''' self.dielectricEq = 'Supcrt' '''The dielectric equation input. The default is Sverjensky.''' self.ForceSupcrt = True '''The option to force supcrt for P < 5 kb. Default is set to true''' self.WaterFreeEq = 'D&H 1978' '''The option for the Water free energy equation. Options are D&H 1978, integral, and custom Default is Delaney and Hegelson 1978.''' self.DisplayVolOpt = True '''The option to display volume, default set to true''' self.PsatDisplayVol = True '''The option to display volume under Psat conditions. Default is set to true.''' self.DisplayVol = True '''Another display volume option. Default to true.''' self.equation = 1 '''A variable that stores the number of the density of water equation. Needs to be renamed''' self.diaEq = 1 '''A variable that stores the number of dielectric constant equation.''' self.psat = True '''A variable that stores the Psat option defined by input''' self.waterDensity = 1 '''A variable that stores the number of the density of water equation.''' # Input Arrays self.aqueousInputs = [] '''The array of aqueous inputs and multipliers defined by a user''' self.mineralInputs = [] '''The array of mineral inputs and multipliers defined by a user''' self.gasInputs = [] '''The array of gas inputs and multipliers defined by a user''' self.waterInputs = [] '''An array that defines if water is used in the input and hOw mUcH wAtEr?''' # Input Matrices self.inGasMat = [] '''A matrix that stores in gasseous inputs with their properties from the dicitonary inputs''' self.inAqMat = [] '''A matrix that stores in aqueous inputs with their properties from the dicitonary inputs''' # Output Arrays self.aqueousOutputs = [] '''The array of aqueous outputs and multipliers defined by a user''' self.mineralOutputs = [] '''The array of mineral outputs and multipliers defined by a user''' self.gasOutputs = [] '''The array of gas outputs and multipliers defined by a user''' self.waterOutputs = [] '''An array that defines if water is used in the outputand hOw mUcH wAtEr?''' # Output Matrices self.outGasMat = [] '''A matrix that stores in gasseous outputs with their properties from the dicitonary inputs''' self.outAqMat = [] '''A matrix that stores in aqueous outputs with their properties from the dicitonary inputs''' # Arrays used for Calculations self.tempUsed = [] '''An array set by the set_TPRho method that contains all the temperatures used for calculation in celsius''' self.pressureUsed = [] '''An array set by the set_TPRho method that contains all the pressures used for calculation''' self.tKelvin = [] '''An array set by the set_TPRho method that contains all the temperatures used for calculation in Kelvin''' self.RhoWatArr = [] '''An array set by the set_TPRho method that contains calculated water densities at the temperatures and pressures used ''' self.DiaArr = [] '''An array set by the set_TPRho method that contains calculated dielectric constants at temp/pressure used''' self.QArr = [] '''An array set by the set_TPRho method that contains calculated Q constants at temp/pressure used''' self.GibbsH2O = [] '''A collection of the gibbs of water values.''' # Collections of Custom Values self.dielectricCollection = [] '''If custom values are used for the dielectric constant this will store them to be queried by the custom function''' self.gibbsCollection = [] '''If custom values are used for the gibbs of water this will store them to be queried by the custom function''' self.densityCollection = [] '''If custom values are used for the density of water this will store them to be queried by the custom function''' # Calculated Matrices self.gasInpGibbs = [] '''Used for debugging, stores the free energy changes of gases''' self.aqInpGibbs = [] '''Used for debugging, stores the free energy changes of aqueous inputs''' self.gasInpV = [] '''Used for debugging, stores the volume changes of gasseous inputs''' self.aqInpV = [] '''Used for debugging, stores the volume changes of aqueous inputs''' self.gasOutGibbs = [] '''Used for debugging, stores the free energy changes of gasseous inputs''' self.aqOutGibbs = [] '''Used for debugging, stores the free energy changes of aqueous outputs''' self.gasOutV = [] '''Used for debugging, stores the volume changes of gasseous outputs''' self.aqOutV = [] '''Used for debugging, stores the volume changes of aqueous outputs''' #Mineral Matrices self.mineralInpGibbs = [] '''Used for debugging, stores the free energy changes of mineral inputs''' self.mineralOutGibbs = [] '''Used for debugging, stores the free energy changes of mineral outputs''' self.mineralInpV = [] '''Used for debugging, stores the volume changes of mineral inputs''' self.mineralOutV = [] '''Used for debugging, stores the volume changes of mineral outputs''' #Water self.waterInpGibbs = [] '''Used for debugging, stores the free energy changes of water outputs''' self.waterInpV = [] '''Used for debugging, stores the volume changes of water inputs''' self.waterOutGibbs = [] '''Used for debugging, stores the free energy changes of water outputs''' self.waterOutV = [] '''Used for debugging, stores the volume changes of water outputs''' # Finals Arrays self.gibbsLst = [] '''A storage variable that lists the gibbs free energy changes. Not sure if necessary''' self.logK = [] '''Stores the list of all logK values with temperatures and pressures''' self.vLst = [] '''A storage variable that lists all the volume changes. Not sure if necessary ''' self.delG = [] '''Stores the list of all delG values with temperatures and pressures''' self.delV = [] '''Stores the list of all delV values with temperatures and pressures''' # Variables to Help with Plotting self.pressRed = [] '''Reduced pressure list with no repeats''' self.tempRed = [] '''Reduced temperature list with no repeats''' self.pLogK = [] '''LogK split into arrays with respect to the number of isobars''' self.pDelG = [] '''DelG split into arrays with respect to the number of isobars''' self.pDelV = [] '''DelV split into arrays with respect to the number of isobars''' self.tLogK = [] '''LogK split into arrays with respect to the number of isotherms''' self.tDelG = [] '''DelG split into arrays with respect to the number of isotherms''' self.tDelV = [] '''DelV split into arrays with respect to the number of isotherms''' # Variables to run SUPCRTBL self.proc = None '''Needed to run supcrt''' self.pout = None '''Needed to run supcrt''' self.pin = None '''Needed to run supcrt''' self.supcrtFile = None '''Stores the most recently run SUPCRT file, or none if none have been run''' self.supcrtOut = None '''Stores the output from calculate_supcrt''' def clear(self): '''Clears variables''' self.__init__() return def set_inputs(self): '''Call this to set the input Arrays. This is not dependent on anything else being called first.''' # A list of integers intLst = ['1','2','3','4', '5', '6','7', '8', '9', '10', '11'] # Mineral Loop mineralCount = 0 aqCount = 0 gasCount = 0 self.mineralInputs = [] self.aqueousInputs = [] self.gasInputs = [] self.waterInputs = [] while mineralCount < 15: mineralCount += 1 validBool = False while not validBool: inp = input('Input Mineral Species') # can insert mineral validation here if possible if inp in mineralDictionary: validBool = True elif inp == "": validBool = True else: print('Your Species is not in the list, please check your spelling') continue validBool2 = False while not validBool2: inp2 = input('Input Mineral Species Multiplier') if inp2 in intLst: validBool2 = True elif inp == "": validBool2 = True else: print('Your multiplier is invalid, please check to make sure this is an integer') if inp == "": break self.mineralInputs.append([inp, inp2]) while aqCount <15: aqCount += 1 validBool = False while not validBool: inp = input('Input Aqueous Species') if inp in nameLst: validBool = True elif inp == "": validBool = True else: print('Your Species is not in the list, please check your spelling') continue validBool2 = False if validBool: while not validBool2: inp2 = input('Input Aqueous Species Multiplier') if inp2 in intLst: validBool2 = True elif inp == "": validBool2 = True else: print('Your multiplier is invalid, please check to make sure this is an integer') if inp == "": break self.aqueousInputs.append([inp, inp2]) while gasCount < 15: gasCount += 1 validBool = False while not validBool: inp = input('Input Gas Species') if inp in GasLst: validBool = True elif inp == "": validBool = True else: print('Your Species is not in the list, please check your spelling') continue if validBool: validBool2 = False while not validBool2: inp2 = input('Input Gas Species Multiplier') if inp2 in intLst: validBool2 = True elif inp == "": validBool2 = True else: print('Your multiplier is invalid, please check to make sure this is an integer') if inp == "": break self.gasInputs.append([inp, inp2]) # Water validBool3 = False while not validBool3: inpWater = input('Would you like to use water? (yes/no)') if inpWater in ['yes', 'no']: validBool3 = True else: print('Please answer yes or no') continue if inpWater == 'yes': validBool3 = False while not validBool3: m3 = input('Enter enter water Multiplier') if m3 in intLst: validBool3 = True else: print('Please enter a valid integer multiplier ') else: m3 = 0 self.waterInputs.append([inpWater, m3]) return def set_outputs(self): '''Call this to set the output Arrays. This is not dependent on anything else being called first.''' # A list of integers intLst = ['1','2','3','4', '5', '6','7', '8', '9', '10', '11'] # Mineral Loop mineralCount = 0 aqCount = 0 gasCount = 0 self.mineralOutputs = [] self.aqueousOutputs = [] self.gasOutputs = [] self.waterOutputs = [] while mineralCount < 15: mineralCount += 1 validBool = False while not validBool: inp = input('Output Mineral Species') # can insert mineral validation here if possible validBool = True validBool2 = False while not validBool2: inp2 = input('Output Mineral Species Multiplier') if inp2 in intLst: validBool2 = True elif inp == "": validBool2 = True else: print('Your multiplier is invalid, please check to make sure this is an integer') if inp == "": break self.mineralOutputs.append([inp, inp2]) while aqCount <15: aqCount += 1 validBool = False while not validBool: inp = input('Output Aqueous Species') if inp in nameLst: validBool = True elif inp == "": validBool = True else: print('Your Species is not in the list, please check your spelling') continue validBool2 = False if validBool: while not validBool2: inp2 = input('Output Aqueous Species Multiplier') if inp2 in intLst: validBool2 = True elif inp == "": validBool2 = True else: print('Your multiplier is invalid, please check to make sure this is an integer') if inp == "": break self.aqueousOutputs.append([inp, inp2]) while gasCount < 15: gasCount += 1 validBool = False while not validBool: inp = input('Input Gas Species') if inp in GasLst: validBool = True elif inp == "": validBool = True else: print('Your Species is not in the list, please check your spelling') continue validBool2 = False if validBool: while not validBool2: inp2 = input('Input Gas Species Multiplier') if inp2 in intLst: validBool2 = True elif inp == "": validBool2 = True else: print('Your multiplier is invalid, please check to make sure fthis is an integer') if inp == "": break self.gasOutputs.append([inp, inp2]) # Water validBool3 = False while not validBool3: outWater = input('Would you like to use water in the output? (yes/no)') if outWater in ['yes', 'no']: validBool3 = True else: print('Please answer yes or no') if outWater == 'yes': validBool3 = False while not validBool3: m3 = input('Enter enter water Multiplier') if m3 in intLst: validBool3 = True else: print('Please enter a valid integer multiplier ') else: m3 = 0 self.waterOutputs.append([outWater, m3]) return def set_preferences(self): '''A function that prompts for user inputs. This is not dependent on anything else being called first. Defaults are set to be identical to the example calculation on the Deep Earth Water Model Excel Sheet.''' validBool = False while not validBool: ptInp = input('Which P-T input would you like to use? "Custom", "Regular", or "Psat"') if ptInp in ['Custom', 'Regular', 'Psat']: validBool = True self.ptInput = ptInp else: print('Please enter one of the provided options') validBool = False while not validBool: RhoOfwater = input('Which density of water would you like to use? "Z&D 2005", "Z&D 2009", or "Custom"') if RhoOfwater in ['Z&D 2005', 'Z&D 2009', 'Custom']: validBool = True self.RhoOfWater = RhoOfwater else: print('Please enter one of the provided options') validBool = False while not validBool: force = input('Force Custom? (yes/no)') if force == 'yes': validBool = True elif force == 'no': validBool = True self.forceCustom = False else: print('Please enter one of the provided options') validBool = False while not validBool: dia = input('Dielectric Constant Equation Option: "Supcrt", "Franck", "Fernandez", "Sverjensky", or "Custom"') if dia in ['Supcrt', 'Franck', 'Fernandez', 'Sverjensky','Custom']: validBool = True self.dielectricEq = dia else: print('Please enter one of the provided options') validBool = False while not validBool: forceS = input('Force Supcrt? (yes/no)') if forceS == 'yes': validBool = True elif forceS == 'no': validBool = True self.ForceSupcrt = False else: print('Please enter one of the provided options') validBool = False while not validBool: freeE = input('Water Free Energy Equation Option: "D&H 1978", "Integral", "Custom"') if freeE in ['D&H 1978', 'Integral', 'Custom']: validBool = True self.WaterFreeEq = freeE validBool = False while not validBool: dispO = input('Display Volume Option? (yes/no)') if dispO == 'yes': validBool = True elif dispO == 'no': validBool = True self.DisplayVolOpt = False else: print('Please enter one of the provided options') validBool = False while not validBool: PsatdispO = input('Psat Display Volume Option? (yes/no)') if PsatdispO == 'yes': validBool = True elif PsatdispO == 'no': validBool = True self.PsatDisplayVol = False else: print('Please enter one of the provided options') validBool = False while not validBool: dispV = input('Display Volume? (yes/no)') if dispV == 'yes': validBool = True elif dispV == 'no': validBool = True self.DisplayVol = False else: print('Please enter one of the provided options') if self.WaterFreeEq == "Custom" or self.dielectricEq == "Custom" or self.RhoOfWater == "Custom": self.dielectricCollection, self.densityCollection, self.gibbsCollection = self.import_custom_sheets() return def import_custom_sheets(self): '''A helper function to import custom data from the Deep Earth Water Model. This only currently works for an unmodified Deep Earth Water Model Sheet format (6_23_20). This is not dependent on anything else being called first.''' diaL = pd.read_csv(diePath, header = None) dia = diaL.to_numpy() dia = dia[4:, 1:] diaTrim = dia[1:, 1:] diaCollection = [] for row in range(len(diaTrim)): for pressure in range(len(diaTrim[0])): # in form pressure, temperature, value diaCollection.append([dia[0][pressure + 1], dia[row + 1][0], diaTrim[row][pressure]]) watDen = pd.read_csv(denPath, header = None) w = watDen.to_numpy() w = w[4:, 1:] wTrim = w[1:,1:] watDenCollection = [] for row in range(len(wTrim)): for pressure in range(len(wTrim[0])): # in form pressure, temperature, value watDenCollection.append([w[0][pressure + 1], w[row + 1][0], wTrim[row][pressure]]) gibbsOfWater = pd.read_csv(gPath, header = None) gibbs = gibbsOfWater.to_numpy() gibbs = gibbs[3:,:] gibbsTrim = gibbs[1:, 1:] gibbsCollection = [] for row in range(len(gibbsTrim)): for pressure in range(len(gibbsTrim[0])): # in form pressure, temperature, value gibbsCollection.append([gibbs[0][pressure + 1], gibbs[row + 1][0], gibbsTrim[row][pressure]]) return diaCollection, watDenCollection, gibbsCollection def set_TPRho(self): '''Sets arrays of temperature, pressure, water density, and Q to be used in the model based on user input. Requires that the input and output arrays have been set up otherwise it will return a divide by 0 error in the calculations.''' pressArr = [] tempArr = [] self.RhoWatArr = [] self.DiaArr = [] self.QArr =[] self.gibbsLst = [] self.logK = [] self.vLst = [] self.delG = [] self.delV = [] if self.ptInput == "Custom": ptSheet = pd.read_csv(inpPath,encoding= 'unicode_escape', header = None) ptFinder = ptSheet.to_numpy() tempArr = [float(i[1]) for i in ptFinder[4:]] pressArr = [float(i[0]) for i in ptFinder[4:]] elif self.ptInput == "Regular": validBool = False while not validBool: try: templow = int(input('Input the minimum temperature')) temphigh = int(input('Input the maximum temperature')) tempstep = int(input('Input the temperature step')) pmin = float(input('Input the minimum pressure (Kb)')) pmax = float(input('Input the maximum pressure (Kb)')) pstep = float(input('Input the pressure step (Kb)')) validBool = True except ValueError: print('You have entered a non-integer value, please start again') tempArr = np.arange(start= templow, stop = temphigh + .00001, step = tempstep) parrHelp = np.arange(start= pmin, stop = pmax + .00001, step = pstep) for i in range(len(parrHelp)): pressArr.append([parrHelp[i]]* len(tempArr)) pressArr = np.multiply(pressArr, 1000) tempArr = [tempArr] * len(parrHelp) elif self.ptInput == "Psat": validBool = False while not validBool: try: templow = int(input('Input the minimum temperature')) temphigh = int(input('Input the mamximum temperature')) tempstep = int(input('Input the temperature step')) validBool = True except ValueError: print('You have entered a non-integer value, please start again') tempArr = np.arange(start= templow, stop = temphigh + 1, step = tempstep) for i in range(len(tempArr)): if tempArr[i] < 100: pressArr.append(1) else: pressArr.append(2.1650906415E-11*np.double(tempArr[i])**5 + 0.0008467019353*np.double(tempArr[i])**2 - 0.17973651666*tempArr[i] + 10.7768850763807) else: # If I've done the checking correctly above it should never reach this raise ValueError("You have not set your options yet, please set them before continuing") self.tempUsed = np.ndarray.flatten(np.asarray(tempArr)) self.pressureUsed = np.ndarray.flatten(np.asarray(pressArr)) self.tKelvin = np.add(self.tempUsed, 273.15) # code to set options in a way the equations can understand if self.ptInput == "Psat": self.psat = True else: self.psat = False if self.RhoOfWater =='Z&D 2005': self.equation = 1 elif self.RhoOfWater == 'Z&D 2009': self.equation = 2 else: self.equation = 3 if self.dielectricEq == "Supcrt": self.diaEq = 1 elif self.dielectricEq == "Franck": self.diaEq = 2 elif self.dielectricEq == "Fernandez": self.diaEq = 3 elif self.dielectricEq == "Sverjensky": self.diaEq = 4 else: self.diaEq = 5 # write code to take in custom Rho, G, and Water Values here self.densityCollection = np.asarray(self.densityCollection).astype(float) self.dielectricCollection = np.asarray(self.dielectricCollection).astype(float) self.gibbsCollection = np.asarray(self.gibbsCollection).astype(float) # Sets the water density array for i in range(len(self.pressureUsed)): # For the custom array if self.RhoOfWater =="Custom" or (self.forceCustom == True and self.pressureUsed[i] < 1000): idx = np.intersect1d(np.where(np.asarray(self.densityCollection) == self.pressureUsed[i]/1000), np.where(np.asarray(self.densityCollection) == self.tempUsed[i]))[0] if not np.isnan(self.densityCollection[idx][2]): self.RhoWatArr.append(self.densityCollection[idx][2]) else: self.RhoWatArr.append(0) else: self.RhoWatArr.append(DEWEquations.DEWEquations.calculateDensity(self.pressureUsed[i], self.tempUsed[i], self.equation, 0.01, self.psat)) # Sets the dielectric constant array for i in range(len(self.pressureUsed)): # for the custom array if self.dielectricEq == "Custom": idx = np.intersect1d(np.where(np.asarray(self.dielectricCollection) == self.pressureUsed[i]/1000), np.where(np.asarray(self.dielectricCollection) == self.tempUsed[i]))[0] if not np.isnan(self.dielectricCollection[idx][2]): self.DiaArr.append(self.dielectricCollection[idx][2]) else: self.DiaArr.append(0) else: if self.ForceSupcrt == True and self.pressureUsed[i] < 5000 and self.psat == False: self.DiaArr.append(DEWEquations.DEWEquations.calculateEpsilon(self.RhoWatArr[i], self.tempUsed[i], 1, self.psat)) else: self.DiaArr.append(DEWEquations.DEWEquations.calculateEpsilon(self.RhoWatArr[i], self.tempUsed[i], self.diaEq, self.psat)) ### The function works up until this point, I haven't debugged further yet (6_29_20) ### # Sets up the Q array for i in range(len(self.pressureUsed)): if self.DisplayVol == True: try: # Has issues with some Q, not sure if problematic self.QArr.append(float(DEWEquations.DEWEquations.calculateQ(self.pressureUsed[i], self.tempUsed[i], self.RhoWatArr[i], self.equation, self.diaEq, self.psat))*np.double(10)**6) except: self.QArr.append(0) else: self.QArr.append(0) # Sets up custom Gibbs of Water Array: if self.WaterFreeEq == "Custom": for i in range(len(self.pressureUsed)): idx = np.intersect1d(np.where(np.asarray(self.gibbsCollection) == self.pressureUsed[i]/1000), np.where(np.asarray(self.gibbsCollection) == self.tempUsed[i]))[0] if not np.isnan(self.gibbsCollection[idx][2]): self.GibbsH2O.append(self.gibbsCollection[idx][2]) else: self.GibbsH2O.append(0) return def calculate_matrices(self): '''A helper function to aggregate the values to the input and output matrices. It requires both the input and output arrays to be set up to function. It is called within "calculate"''' self.inAqMat = [] self.inGasMat = [] self.outAqMat = [] self.outGasMat = [] for i in self.aqueousInputs: self.inAqMat.append([i[0],symbolDict[i[0]], delGf[i[0]], delHf[i[0]], entropy[i[0]],volume[i[0]],specHeat[i[0]], a1x10[i[0]], a2x10_2[i[0]], a3[i[0]],a4x10_4[i[0]],c1[i[0]],c2x10_4[i[0]],omegax10_5[i[0]],Z[i[0]], i[1]]) for i in self.gasInputs: self.inGasMat.append([i[0],GasSymb[i[0]],GasDelGf[i[0]],GasDelHf[i[0]],GasEntropy[i[0]],GasCp[i[0]], GasA[i[0]], GasBx103[i[0]],GasCx10_5[i[0]],GasT[i[0]], i[1]]) for i in self.aqueousOutputs: self.outAqMat.append([i[0],symbolDict[i[0]], delGf[i[0]], delHf[i[0]], entropy[i[0]],volume[i[0]],specHeat[i[0]], a1x10[i[0]], a2x10_2[i[0]], a3[i[0]],a4x10_4[i[0]],c1[i[0]],c2x10_4[i[0]],omegax10_5[i[0]],Z[i[0]], i[1]]) for i in self.gasOutputs: self.outGasMat.append([i[0],GasSymb[i[0]],GasDelGf[i[0]],GasDelHf[i[0]],GasEntropy[i[0]],GasCp[i[0]], GasA[i[0]], GasBx103[i[0]],GasCx10_5[i[0]],GasT[i[0]],i[1]]) return def calculate_gas(self): '''A helper function to calculate the gasseous columns and output them as a matrix. Specifically returns the arrays gasInGibbs, gasOutGibbs, gasInV, gasOuV. Needs self.tempUsed and self.tKelvin to be set, as well as the input gas matrix. It is called within the calculate function.''' gasInGibbs = [] gasOuGibbs = [] gasInV = [] gasOuV = [] for gas in self.inGasMat: storelst = [] storelst2 =[] storelst.append(gas[0]) storelst.append(gas[10]) storelst2.append(gas[0]) storelst2.append(gas[10]) for i in range(len(self.tempUsed)): if self.DisplayVol == False or self.tempUsed[i] == 0: storelst2.append(0) else: storelst2.append(24.465) for i in range(len(self.tKelvin)): storelst.append(gas[2] - gas[4]*(self.tKelvin[i]-T_r) + gas[6]*(self.tKelvin[i]-T_r - self.tKelvin[i]*np.log(self.tKelvin[i]/T_r)) + gas[7]*(0.001)/2*(2*self.tKelvin[i]*T_r -np.double(self.tKelvin[i])**2 - np.double(T_r) **2) + gas[8]*100000*(np.double(self.tKelvin[i])**2 + np.double(T_r)**2 -2*self.tKelvin[i]*T_r)/(2*self.tKelvin[i]*np.double(T_r)**2)) gasInGibbs.append(storelst) gasInV.append(storelst2) for gas in self.outGasMat: storelst = [] storelst2 = [] storelst.append(gas[0]) storelst.append(gas[10]) storelst2.append(gas[0]) storelst2.append(gas[10]) for i in range(len(self.tempUsed)): if self.DisplayVol == False or self.tempUsed[i] == 0: storelst2.append(0) else: storelst2.append(24.465) for i in range(len(self.tKelvin)): storelst.append(gas[2] - gas[4]*(self.tKelvin[i]-T_r) + gas[6]*(self.tKelvin[i]-T_r - self.tKelvin[i]*np.log(self.tKelvin[i]/T_r)) + gas[7]*(0.001)/2*(2*self.tKelvin[i]*T_r -np.double(self.tKelvin[i])**2 - np.double(T_r) **2) + gas[8]*100000*(np.double(self.tKelvin[i])**2 + np.double(T_r)**2 -2*self.tKelvin[i]*T_r)/(2*self.tKelvin[i]*np.double(T_r)**2)) gasOuGibbs.append(storelst) gasOuV.append(storelst2) if len(gasInGibbs) == 0: gasInGibbs = [np.zeros(len(self.tKelvin) + 2)] if len(gasOuGibbs) == 0: gasOuGibbs = [np.zeros(len(self.tKelvin) + 2)] if len(gasInV) == 0: gasInV = [np.zeros(len(self.tKelvin) + 2)] if len(gasOuV) == 0: gasOuV = [np.zeros(len(self.tKelvin) + 2)] return gasInGibbs, gasOuGibbs, gasInV, gasOuV def calculate_H2O(self): '''This function requires input and output matrices to be set. This is called within the calculate function.''' waterMatInGibbs = [] waterMatOutGibbs = [] waterMatInV = [] waterMatOutV = [] if self.WaterFreeEq == 'D&H 1978': self.waterDensity = 1 elif self.WaterFreeEq == 'Integral': self.waterDensity = 2 else: self.waterDensity = 3 if self.waterInputs[0][0] == 'yes': waterLst = [] waterLst2 = [] waterLst.append('H2O') waterLst.append(self.waterInputs[0][1]) waterLst2.append('H2O') waterLst2.append(self.waterInputs[0][1]) for i in range(len(self.pressureUsed)): #for i in range(len(self.pressureUsed)): if self.WaterFreeEq == 'Custom': try: if self.GibbsH2O[i] == 0: waterLst.append(0) else: waterLst.append(GibbsH2O[i]) except: waterLst.append(GibbsH2O[i]) else: store = DEWEquations.DEWEquations.calculateGibbsOfWater(self.pressureUsed[i], self.tempUsed[i], self.waterDensity, self.equation, self.psat) waterLst.append(store) if self.DisplayVol == True: try: waterLst2.append(18.01528/self.RhoWatArr[i]) except: waterLst2.append(0) continue else: waterLst2.append(0) waterMatInGibbs.append(waterLst) waterMatInV.append(waterLst2) if self.waterOutputs[0][0] =='yes': waterLst = [] waterLst2 = [] waterLst.append('H2O') waterLst.append(self.waterOutputs[0][1]) waterLst2.append('H2O') waterLst2.append(self.waterOutputs[0][1]) for i in range(len(self.pressureUsed)): if self.WaterFreeEq == 'Custom': try: if GibbsH2O[i] == 0: waterLst.append(0) else: waterLst.append(GibbsH2O[i]) except: waterLst.append(GibbsH2O[i]) else: waterLst.append(DEWEquations.DEWEquations.calculateGibbsOfWater(self.pressureUsed[i], self.tempUsed[i], self.waterDensity, self.equation, self.psat)) if self.DisplayVol == True: try: waterLst2.append(18.01528/self.RhoWatArr[i]) except: waterLst2.append(0) else: waterLst2.append(0) waterMatOutGibbs.append(waterLst) waterMatOutV.append(waterLst2) if len(waterMatInGibbs) == 0: waterMatInGibbs = np.zeros((len(self.tKelvin) + 2)) if len(waterMatInV) == 0: waterMatInV = np.zeros((len(self.tKelvin) + 2)) if len(waterMatOutGibbs) == 0: waterMatOutGibbs = np.zeros((len(self.tKelvin) + 2)) if len(waterMatOutV) == 0: waterMatOutV = np.zeros((len(self.tKelvin) + 2)) return waterMatInGibbs, waterMatInV, waterMatOutGibbs, waterMatOutV def calculate_aq(self): '''A helper function to calculate the aqueous columns and output them as a matrix. This is called within calculate.''' aqInGibbs = [] aqOuGibbs = [] aqInV = [] aqOuV = [] for aq in self.inAqMat: storelst = [] storelst2= [] storelst.append(aq[0]) storelst.append(aq[15]) storelst2.append(aq[0]) storelst2.append(aq[15]) for i in range(len(self.tKelvin)): storelst.append(aq[2] - aq[4] * (self.tKelvin[i] - T_r) - aq[11] * (self.tKelvin[i] * np.log(self.tKelvin[i]/T_r) - self.tKelvin[i] + T_r) - aq[12]*(10**4)*(((1/(self.tKelvin[i]-Theta)) - (1/(T_r-Theta)))*((Theta-self.tKelvin[i])/(Theta))- (self.tKelvin[i]/(Theta*Theta)) * np.log((T_r*(self.tKelvin[i]-Theta))/(self.tKelvin[i]*(T_r-Theta)))) + aq[7]*(10**-1)*(self.pressureUsed[i]-Pr) + aq[8]*(10**2)*np.log((Psy+self.pressureUsed[i])/(Psy+Pr)) + (1/(self.tKelvin[i]-Theta))*(aq[9]*(self.pressureUsed[i]-Pr) + aq[10]*(10**4)*np.log((Psy+self.pressureUsed[i])/(Psy+Pr))) + DEWEquations.DEWEquations.calculateOmega(self.pressureUsed[i],self.tempUsed[i],self.RhoWatArr[i],aq[0],aq[13]*(10**5),aq[14])*((1/self.DiaArr[i])-1) - aq[13]*(10**5)*((1/E_PrTr)-1) + aq[13]*(10**5)*Upsilon*(self.tKelvin[i]-T_r)) for i in range(len(self.pressureUsed)): storelst2.append((aq[7]/10 + aq[8]*100/(Psy+self.pressureUsed[i]) + (aq[9] + aq[10]*10000/(Psy+self.pressureUsed[i]))/(self.tKelvin[i]-Theta) - DEWEquations.DEWEquations.calculateOmega(self.pressureUsed[i],self.tempUsed[i],self.RhoWatArr[i],aq[0],aq[13]*(10**5),aq[14])*(self.QArr[i]*10**-6 ) + (1/self.DiaArr[i] - 1) * DEWEquations.DEWEquations.calculate_domegadP(self.pressureUsed[i],self.tempUsed[i],self.RhoWatArr[i],aq[0],aq[13]*(10**5),aq[14],self.equation,self.psat))*41.84) aqInGibbs.append(storelst) aqInV.append(storelst2) for aq in self.outAqMat: storelst = [] storelst2= [] storelst.append(aq[0]) storelst.append(aq[15]) storelst2.append(aq[0]) storelst2.append(aq[15]) for i in range(len(self.tKelvin)): storelst.append(aq[2] - aq[4] * (self.tKelvin[i] - T_r) - aq[11] * (self.tKelvin[i] * np.log(self.tKelvin[i]/T_r) - self.tKelvin[i] + T_r) - aq[12]*(10**4)*(((1/(self.tKelvin[i]-Theta)) - (1/(T_r-Theta)))*((Theta-self.tKelvin[i])/(Theta))- (self.tKelvin[i]/(Theta*Theta)) * np.log((T_r*(self.tKelvin[i]-Theta))/(self.tKelvin[i]*(T_r-Theta)))) + aq[7]*(10**-1)*(self.pressureUsed[i]-Pr) + aq[8]*(10**2)*np.log((Psy+self.pressureUsed[i])/(Psy+Pr)) + (1/(self.tKelvin[i]-Theta))*(aq[9]*(self.pressureUsed[i]-Pr) + aq[10]*(10**4)*np.log((Psy+self.pressureUsed[i])/(Psy+Pr))) + DEWEquations.DEWEquations.calculateOmega(self.pressureUsed[i],self.tempUsed[i],self.RhoWatArr[i],aq[0],aq[13]*(10**5),aq[14])*((1/self.DiaArr[i])-1) - aq[13]*(10**5)*((1/E_PrTr)-1) + aq[13]*(10**5)*Upsilon*(self.tKelvin[i]-T_r)) for i in range(len(self.pressureUsed)): storelst2.append((aq[7]/10 + aq[8]*100/(Psy+self.pressureUsed[i]) + (aq[9] + aq[10]*10000/(Psy+self.pressureUsed[i]))/(self.tKelvin[i]-Theta) - DEWEquations.DEWEquations.calculateOmega(self.pressureUsed[i],self.tempUsed[i],self.RhoWatArr[i],aq[0],aq[13]*(10**5),aq[14])*(self.QArr[i]*10**-6 ) + (1/self.DiaArr[i] - 1) * DEWEquations.DEWEquations.calculate_domegadP(self.pressureUsed[i],self.tempUsed[i],self.RhoWatArr[i],aq[0],aq[13]*(10**5),aq[14],self.equation,self.psat))*41.84) aqOuGibbs.append(storelst) aqOuV.append(storelst2) if len(aqInGibbs) == 0: aqInGibbs = [np.zeros(len(self.tKelvin) + 2)] if len(aqOuGibbs) == 0: aqOuGibbs = [np.zeros(len(self.tKelvin) + 2)] if len(aqInV) == 0: aqInV = [np.zeros(len(self.tKelvin) + 2)] if len(aqOuV) == 0: aqOuV = [np.zeros(len(self.tKelvin) + 2)] return aqInGibbs, aqOuGibbs, aqInV, aqOuV def calculate(self): '''The function called that will update all of the parameters. It has no outputs, but allows certain arrays to be queried. ''' self.calculate_matrices() self.waterInpGibbs, self.waterInpV, self.waterOutGibbs, self.waterOutV = self.calculate_H2O() self.aqInpGibbs, self.aqOutGibbs, self.aqInpV, self.aqOutV = self.calculate_aq() self.gasInpGibbs, self.gasOutGibbs, self.gasInpV, self.gasOutV = self.calculate_gas() G1 = np.delete(np.asarray(self.waterInpGibbs), [0,1]).astype(np.float) * int(self.waterInputs[0][1]) V1 = np.delete(np.asarray(self.waterInpV), [0,1]).astype(np.float) * int(self.waterInputs[0][1]) G4 = np.delete(np.asarray(self.waterOutGibbs), [0,1]).astype(np.float) * int(self.waterOutputs[0][1]) V4 = np.delete(np.asarray(self.waterOutV), [0,1]).astype(np.float) * int(self.waterOutputs[0][1]) # Gas Loops G3, V3 = ([], []) for i in range(len(self.gasInpGibbs)): G3.append(np.multiply(np.delete(np.asarray(self.gasInpGibbs[i]), [0,1]).astype(np.float), int(self.gasInpGibbs[i][1]))) V3.append(np.multiply(np.delete(np.asarray(self.gasInpV[i]), [0,1]).astype(np.float), int(self.gasInpV[i][1]))) G3 = np.sum(G3, axis = 0) V3 = np.sum(V3, axis = 0) G6, V6 = ([], []) for i in range(len(self.gasOutGibbs)): G6.append(np.multiply(np.delete(np.asarray(self.gasOutGibbs[i]), [0,1]).astype(np.float), int(self.gasOutGibbs[i][1]))) V6.append(np.multiply(np.delete(np.asarray(self.gasOutV[i]), [0,1]).astype(np.float), int(self.gasOutV[i][1]))) G6 = np.sum(G6, axis = 0) V6 = np.sum(V6, axis = 0) # Aqueous Inputs G2, V2 = ([], []) for i in range(len(self.aqInpGibbs)): G2.append(np.multiply(np.delete(np.asarray(self.aqInpGibbs[i]), [0,1]).astype(np.float), int(self.aqInpGibbs[i][1]))) V2.append(np.multiply(np.delete(np.asarray(self.aqInpV[i]), [0,1]).astype(np.float), int(self.aqInpV[i][1]))) G2 = np.sum(G2, axis = 0) V2 = np.sum(V2, axis = 0) G5, V5 = ([], []) for i in range(len(self.aqOutGibbs)): G5.append(np.multiply(np.delete(np.asarray(self.aqOutGibbs[i]), [0,1]).astype(np.float), int(self.aqOutGibbs[i][1]))) V5.append(np.multiply(np.delete(np.asarray(self.aqOutV[i]), [0,1]).astype(np.float), int(self.aqOutV[i][1]))) G5 = np.sum(G5, axis = 0) V5 = np.sum(V5, axis = 0) dG = [np.sum([G4, G5, G6], axis = 0) - np.sum([G1, G2, G3], axis = 0)] dV = [np.sum([V4, V5, V6], axis = 0) - np.sum([V1, V2, V3], axis = 0)] # Adding the mineral contributions if they exist, must be at the same temperatures and pressures if len(self.mineralInputs) > 0: for i in range(len(self.mineralInputs)): if self.psat == False: myMinPath = mineralDictionary2 else: myMinPath = mineralDictionary for temp in self.tempUsed: self.mineralInpGibbs.append(np.multiply(myMinPath[self.mineralInputs[i][0]]['delG'][myMinPath[self.mineralInputs[i][0]]['Temperature'].index(temp)], int(self.mineralInputs[i][1]))) self.mineralInpV.append(np.multiply(myMinPath[self.mineralInputs[i][0]]['delV'][myMinPath[self.mineralInputs[i][0]]['Temperature'].index(temp)], int(self.mineralInputs[i][1]))) dG = np.sum([dG, np.sum([self.mineralInpGibbs], axis = 0)], axis = 0) dV = np.sum([dV, np.sum([self.mineralInpV], axis = 0)], axis = 0) if len(self.mineralOutputs) > 0: for i in range(len(self.mineralOutputs)): for temp in self.tempUsed: self.mineralOutGibbs.append(np.multiply(myMinPath[self.mineralOutputs[i][0]]['delG'][myMinPath[self.mineralOutputs[i][0]]['Temperature'].index(temp)], int(self.mineralInputs[i][1]))) self.mineralOutV.append(np.multiply(myMinPath[self.mineralOutputs[i][0]]['delV'][myMinPath[self.mineralOutputs[i][0]]['Temperature'].index(temp)], int(self.mineralInputs[i][1]))) dG = np.sum([dG, -np.sum([self.mineralOutGibbs],axis = 0)], axis = 0) dV = np.sum([dV, -np.sum([self.mineralOutV],axis = 0)], axis = 0) self.logK = [] self.delG = [] self.delV = [] for i in range(len(dG[0])): self.logK.append([-dG[0][i]/(2.302585*self.tKelvin[i]*bigR), self.tempUsed[i], self.pressureUsed[i]]) self.delG.append([dG[0][i], self.tempUsed[i], self.pressureUsed[i]]) self.delV.append([dV[0][i], self.tempUsed[i], self.pressureUsed[i]]) # Sets plotting arrays for convenient plotting of isotherms/isobars if self.ptInput!= 'Psat' or self.psat == False: self.pressRed = list(set(self.pressureUsed)) self.tempRed = list(set(self.tempUsed)) self.pressRed.sort() self.tempRed.sort() temppLogK = defaultdict(list) temppDelG = defaultdict(list) temppDelV = defaultdict(list) temptLogK = defaultdict(list) temptDelG = defaultdict(list) temptDelV = defaultdict(list) for logK, temp, pressure in self.logK: temppLogK[pressure].append(logK) temptLogK[temp].append(logK) for delG, temp, pressure in self.delG: temppDelG[pressure].append(delG) temptDelG[temp].append(delG) for delV, temp, pressure in self.delV: temppDelV[pressure].append(delV) temptDelV[temp].append(delV) for item in temppDelG: self.pDelG.append(temppDelG[item]) for item in temppDelV: self.pDelV.append(temppDelV[item]) for item in temppLogK: self.pLogK.append(temppLogK[item]) for item in temptDelG: self.tDelG.append(temptDelG[item]) for item in temptDelV: self.tDelV.append(temptDelV[item]) for item in temptLogK: self.tLogK.append(temptLogK[item]) return ############################### ####### Methods to auto ####### ############################### def set_tp(self, pt_arr): '''Setting the PT values, but automated for the helperfunction. Can also be used to quick set tp with prompted input''' pressArr = [] tempArr = [] self.RhoWatArr = [] self.DiaArr = [] self.QArr =[] self.gibbsLst = [] self.logK = [] self.vLst = [] self.delG = [] self.delV = [] if self.ptInput == "Custom": ptSheet =pd.read_csv(inpPath,encoding= 'unicode_escape', header = None) ptFinder = ptSheet.to_numpy() tempArr = [float(i[1]) for i in ptFinder[4:]] pressArr = [float(i[0]) for i in ptFinder[4:]] elif self.ptInput == "Regular": try: templow = pt_arr[0][0] temphigh =pt_arr[0][1] tempstep = pt_arr[0][2] pmin = pt_arr[1][0] pmax = pt_arr[1][1] pstep = pt_arr[1][2] except ValueError: print('Your PT array is not formatted correctly. Please use the format [[tmin, tmax, tstep][pmin, pmax, pstep]]') tempArr = np.arange(start= templow, stop = temphigh + 1, step = tempstep) parrHelp = np.arange(start= pmin, stop = pmax + 1, step = pstep) for i in range(len(parrHelp)): pressArr.append([parrHelp[i]]* len(tempArr)) pressArr = np.multiply(pressArr, 1000) tempArr = [tempArr] * len(parrHelp) elif self.ptInput == "Psat": try: templow = pt_arr[0] temphigh = pt_arr[1] tempstep = pt_arr[2] validBool = True except ValueError: print('Your input is not formatted correctly. Please use the format for psat of [tmin, tmax, tstep]') tempArr = np.arange(start= templow, stop = temphigh + 1, step = tempstep) for i in range(len(tempArr)): if tempArr[i] < 100: pressArr.append(1) else: pressArr.append(2.1650906415E-11*np.double(tempArr[i])**5 + 0.0008467019353*np.double(tempArr[i])**2 - 0.17973651666*tempArr[i] + 10.7768850763807) else: # If I've done the checking correctly above it should never reach this raise ValueError("You have not set your options yet, please set them before continuing") self.tempUsed = np.ndarray.flatten(np.asarray(tempArr)) self.pressureUsed = np.ndarray.flatten(np.asarray(pressArr)) self.tKelvin = np.add(self.tempUsed, 273.15) # code to set options in a way the equations can understand if self.ptInput == "Psat": self.psat = True else: self.psat = False if self.RhoOfWater =='Z&D 2005': self.equation = 1 elif self.RhoOfWater == 'Z&D 2009': self.equation = 2 else: self.equation = 3 if self.dielectricEq == "Supcrt": self.diaEq = 1 elif self.dielectricEq == "Franck": self.diaEq = 2 elif self.dielectricEq == "Fernandez": self.diaEq = 3 elif self.dielectricEq == "Sverjensky": self.diaEq = 4 else: self.diaEq = 5 # write code to take in custom Rho, G, and Water Values here self.densityCollection = np.asarray(self.densityCollection).astype(float) self.dielectricCollection = np.asarray(self.dielectricCollection).astype(float) self.gibbsCollection = np.asarray(self.gibbsCollection).astype(float) # Sets the water density array for i in range(len(self.pressureUsed)): # For the custom array if self.RhoOfWater =="Custom" or (self.forceCustom == True and self.pressureUsed[i] < 1000): idx = np.intersect1d(np.where(np.asarray(self.densityCollection).astype(float) == self.pressureUsed[i]/1000), np.where(np.asarray(self.densityCollection).astype(float) == self.tempUsed[i]))[0] if not np.isnan(self.densityCollection[idx][2]): self.RhoWatArr.append(self.densityCollection[idx][2]) else: self.RhoWatArr.append(0) else: self.RhoWatArr.append(DEWEquations.DEWEquations.calculateDensity(self.pressureUsed[i], self.tempUsed[i], self.equation, 0.01, self.psat)) # Sets the dielectric constant array for i in range(len(self.pressureUsed)): # for the custom array if self.dielectricEq == "Custom": idx = np.intersect1d(np.where(np.asarray(self.dielectricCollection).astype(float) == self.pressureUsed[i]/1000), np.where(np.asarray(self.dielectricCollection).astype(float) == self.tempUsed[i]))[0] if not np.isnan(self.dielectricCollection[idx][2]): self.DiaArr.append(self.dielectricCollection[idx][2]) else: self.DiaArr.append(0) else: if self.ForceSupcrt == True and self.pressureUsed[i] < 5000 and self.psat == False: self.DiaArr.append(DEWEquations.DEWEquations.calculateEpsilon(self.RhoWatArr[i], self.tempUsed[i], 1, self.psat)) else: self.DiaArr.append(DEWEquations.DEWEquations.calculateEpsilon(self.RhoWatArr[i], self.tempUsed[i], self.diaEq, self.psat)) # Sets up the Q array for i in range(len(self.pressureUsed)): if self.DisplayVol == True: try: self.QArr.append(float(DEWEquations.DEWEquations.calculateQ(self.pressureUsed[i], self.tempUsed[i], self.RhoWatArr[i], self.equation, self.diaEq, self.psat))*np.double(10)**6) except: self.QArr.append(0) else: self.QArr.append(0) # Sets up custom Gibbs of Water Array: if self.WaterFreeEq == "Custom": for i in range(len(self.pressureUsed)): idx = np.intersect1d(np.where(np.asarray(self.gibbsCollection).astype(float) == self.pressureUsed[i]/1000), np.where(np.asarray(self.gibbsCollection).astype(float) == self.tempUsed[i]))[0] if not np.isnan(self.gibbsCollection[idx][2]): self.GibbsH2O.append(self.gibbsCollection[idx][2]) else: self.GibbsH2O.append(0) return def run(self, pt_arr, min_inp =[], aq_inp = [], g_inp = [], h2o_inp = 0, min_out = [],aq_out =[], g_out = [],h2o_out = 0, ptInp = 'Psat', rhoWat = 'Z&D 2005', forceBool = False, dieEQ = 'Supcrt', forceSC = True, WFEQ ='D&H 1978', dsV = True, pdsV = True, DV = True, EQ = 1, dEQ = 1, pst = True, mWn = 1, makeP = False): if h2o_inp > 0: self.waterInputs = [['yes',h2o_inp]] else: self.waterInputs = [['no',0]] if h2o_out > 0: self.waterOutputs = [['yes',h2o_out]] else: self.waterOutputs = [['no',0]] self.mineralInputs = min_inp self.aqueousInputs = aq_inp self.gasInputs = g_inp self.mineralOutputs = min_out self.aqueousOutputs = aq_out self.gasOutputs = g_out self.ptInput = ptInp self.RhoOfWater = rhoWat self.forceCustom = forceBool self.dielectricEq = dieEQ self.ForceSupcrt = forceSC self.WaterFreeEq = WFEQ self.DisplayVolOpt = dsV self.PsatDisplayVol = pdsV self.DisplayVol = DV self.equation = EQ self.diaEq = dEQ self.psat = pst self.waterDensity = mWn # to actually run: self.set_tp(pt_arr) self.calculate() if makeP == True: self.make_plots() return ###### MAKE PLOTS########### def make_plots(self): '''A final function that the user calls to make the plots possible in the Excel spreadsheet. ''' plt.clf() ###### PSAT PLOTS ####### if self.psat == True or self.ptInput =='Psat': plt.figure() plt.plot(self.pressureUsed, [i[0] for i in self.logK]) plt.xlabel('Pressure (bar)') plt.ylabel('LogK') plt.title('Pressure vs. LogK Psat Curve') plt.show() plt.figure() plt.plot(self.pressureUsed, [i[0] for i in self.delG]) plt.xlabel('Pressure (bar)') plt.ylabel(r'$\Delta$G') plt.title('Pressure vs. $\Delta$G Psat Curve') plt.show() plt.figure() plt.plot(self.pressureUsed, [i[0] for i in self.delV]) plt.xlabel('Pressure (bar)') plt.ylabel('$\Delta$V') plt.title('Pressure vs. $\Delta$V Psat Curve') plt.show() plt.figure() plt.plot(self.tempUsed, [i[0] for i in self.logK]) plt.xlabel(r'Temperature ($^\circ$ C)') plt.ylabel('LogK') plt.title('Temperature vs. LogK Psat Curve') plt.show() plt.figure() plt.plot(self.tempUsed, [i[0] for i in self.delG]) plt.xlabel('Temperature ($^\circ$ C)') plt.ylabel('$\Delta$G') plt.title('Temperature vs. $\Delta$G Psat Curve') plt.show() plt.figure() plt.plot(self.tempUsed, [i[0] for i in self.delV]) plt.xlabel('Temperature ($^\circ$ C)') plt.ylabel('$\Delta$V') plt.title('Temperature vs. $\Delta$V Psat Curve') plt.show() ####### NON PSAT PLOTS ######## else: # T Plots plt.figure() for i in self.pDelG: plt.plot(self.tempRed, i) plt.legend(self.pressRed,bbox_to_anchor=(1.05, 1), title = 'Pressure (bar)', loc='upper left') plt.xlabel('Temperature ($^\circ$C)') plt.ylabel('$\Delta$G') plt.title('Temperature vs. $\Delta$G') plt.show() plt.figure() for i in self.pDelV: plt.plot(self.tempRed, i) plt.legend(self.pressRed,bbox_to_anchor=(1.05, 1), title = 'Pressure (bar)', loc='upper left') plt.xlabel('Temperature ($^\circ$C)') plt.ylabel('$\Delta$V') plt.title('Temperature vs. $\Delta$V') plt.show() plt.figure() for i in self.pLogK: plt.plot(self.tempRed, i) plt.legend(self.pressRed,bbox_to_anchor=(1.05, 1), title = 'Pressure (bar)', loc='upper left') plt.xlabel('Temperature ($^\circ$C)') plt.ylabel('LogK') plt.title('Temperature vs. LogK') plt.show() # P Plots plt.figure() for i in self.tDelG: plt.plot(self.pressRed, i) plt.legend(self.tempRed,bbox_to_anchor=(1.05, 1), title = 'Temperature ($^\circ$C)', loc='upper left') plt.xlabel('Pressure (bar)') plt.ylabel('$\Delta$G') plt.title('Pressure vs. $\Delta$G') plt.show() plt.figure() for i in self.tDelV: plt.plot(self.pressRed, i) plt.legend(self.tempRed,bbox_to_anchor=(1.05, 1), title = 'Temperature ($^\circ$C)', loc='upper left') plt.xlabel('Pressure (bar)') plt.ylabel('$\Delta$V') plt.title('Pressure vs. $\Delta$V') plt.show() plt.figure() for i in self.tLogK: plt.plot(self.pressRed, i) plt.legend(self.tempRed,bbox_to_anchor=(1.05, 1), title = 'Temperature ($^\circ$C)', loc='upper left') plt.xlabel('Pressure (bar)') plt.ylabel('LogK') plt.title('Pressure vs. LogK') plt.show() return ############################# ######### OTHER ############# ############################# def export_to_csv(self): dV = [row[0] for row in self.delV] dG = [row[0] for row in self.delG] lK = [row[0] for row in self.logK] T = [row[1] for row in self.logK] P = [row[2] for row in self.logK] output_array = np.column_stack([T,P, dV,dG,lK]) df = pd.DataFrame(output_array) df.columns = ['Temperature','Pressure','delV','delG','LogK'] name = input('Input the name of the CSV file') finalName = name + ".csv" df.to_csv(finalName, index = False) def options(self): print('Welcome to DEWPython, here are the options you can run:') print('1. DEW(): this initializes a Deep Earth Water Model Object') print(' -The DEW object requires the set_inputs, set_outputs, set_TPRho, and calculate methods to be run.') print(' -You can also utilize the import_custom_sheets method to import custom CSV data') print(' -After calculating you can use the make_plots or export_to_csv methods.') print('2. run_supcrt: this initializes an inline run of SUPCRTBL') print(' -After initializing the SUPCRTBL object, run calculate_supcrt to store the supcrt outputs in arrays') print(' -You can also use run_supcrt on a supcrt ouput file that has already been run by adding the optional argument of the file name') print(' -After this you can run make_supcrt_plots to plot the supcrt files akin the a DEW file') ###################################### ####### METHODS FOR SUPCRT ########### ###################################### def outLoop(self): '''A helper function to allow SUPCRTBL to run''' running = True while(running): line = self.pout.readline().decode(sys.stdout.encoding) print(line, end='') running='\n' in line print('Finished') def outLoop2(self): '''A helper function to allow SUPCRT96 to run''' running = True while(running): line = self.pout.readline().decode(sys.stdout.encoding) running='\n' in line def run_supcrt(self, version = '96'): '''A function that runs the pre-compiled SUPCRTBL found in the file folder''' if version != '96': sup_path = '/'.join(('resources', 'SUPCRTBL.exe')) supPath = pkg_resources.resource_filename(resource_package, sup_path) else: sup_path = '/'.join(('resources', 'supcrt96.exe')) supPath = pkg_resources.resource_filename(resource_package, sup_path) self.proc = subprocess.Popen(supPath,shell = True, stdout = subprocess.PIPE, stdin = subprocess.PIPE, stderr = subprocess.STDOUT) self.pout = self.proc.stdout self.pin = self.proc.stdin threading.Thread(target=self.outLoop).start() while(self.proc.poll() is None): var = input('User Input: ') if '.txt' in var: self.supcrtFile = op.dirname(op.abspath(__file__)) + '\\resources\\' + var inp=bytearray(var +'\n', sys.stdin.encoding) if(self.proc.poll() is None): self.pin.write(inp) self.pin.flush() return def calculate_supcrt_special(self, customFile = None): '''Calculates the output from either SUPCRTBL/SUPCRT96 at isothermal/isobaric temperatures''' returnLst = {} if customFile != None: filename = op.dirname(op.abspath(os.getcwd()))+ '\\' + customFile elif len(self.supcrtFile) ==0: raise ValueError("You haven't run SUPCRT yet") else: filename = self.supcrtFile with open(filename, 'r') as f: impor = f.read() import_data = impor.replace('\t', ' ') split = import_data.split('\n') for i in range(len(split)): try: if 'ISOTHERMS(degC)' in split[i]: finalTemp = " ".join(split[i].split()).split(' ')[5] finalPress = " ".join(split[i+1].split()).split(' ')[6] returnVar = input('Enter reaction title') except: continue if 'STANDARD STATE PROPERTIES OF THE REACTION AT ELEVATED TEMPERATURES AND PRESSURES' in split[i]: subLst = [] temp = [] pres = [] DH2 = [] lgK = [] dlG = [] dlH = [] dlS = [] dlV = [] dlCp = [] subDict = {} for item in split[(i+4):]: if len(item) > 0: subLst = (" ".join(item.split())).split(' ') try: float(subLst[0]) except: continue try: a = subLst[0] b = subLst[1] c = subLst[2] d = subLst[3] e = subLst[4] f = subLst[5] g = subLst[6] h = subLst[7] i = subLst[8] temp.append(a) pres.append(b) DH2.append(c) lgK.append(d) dlG.append(e) dlH.append(f) dlS.append(g) dlV.append(h) dlCp.append(i) if float(subLst[0]) == finalTemp and float(subLst[1]) == finalPress: break except: continue subDict['Temperature'] = [float(i) for i in temp] subDict['Pressure'] = [float(i) for i in pres] DH2Lst = [] lgKLst = [] dlGLst = [] dlHLst = [] dlSLst = [] dlVLst = [] dlCpLst = [] for i in range(len(DH2)): try: DH2Lst.append(float(DH2[i])) except: DH2Lst.append(0) try: lgKLst.append(float(lgK[i])) except: lgKLst.append(0) try: dlGLst.append(float(dlG[i])) except: dlGLst.append(0) try: dlHLst.append(float(dlH[i])) except: dlHLst.append(0) try: dlSLst.append(float(dlS[i])) except: dlSLst.append(0) try: dlVLst.append(float(dlV[i])) except: dlVLst.append(0) try: dlCpLst.append(dlCp[i]) except: dlCpLst.append[0] subDict['DH2O'] = DH2Lst subDict['LogK'] = lgKLst subDict['delG'] = dlGLst subDict['delH'] = dlHLst subDict['delS'] = dlSLst subDict['delV'] = dlVLst subDict['delCp'] = dlCpLst returnLst[returnVar] = subDict self.supcrtOut = returnLst def supcrt_inp(self, rxn_lst, title, reaction_type = 'psat'): '''Takes a list of reaction lists (comprised of tuples) and runs supcrt''' for reaction in rxn_lst: sup_path = '/'.join(('resources', 'supcrt96.exe')) supPath = pkg_resources.resource_filename(resource_package, sup_path) self.proc = subprocess.Popen(supPath,stdout=subprocess.PIPE, stdin=subprocess.PIPE,stderr=subprocess.STDOUT, shell=True) self.pout = self.proc.stdout self.pin = self.proc.stdin it = 0 rxnVar = 'realReac.con' if reaction_type != 'psat': rxnVar = 'Xtend.con' if len(title) < 1: title = input('What is the title of your reaction?') comm = ['n', 'updateSlop1.dat', '2', rxnVar, '2', '1', title] for component in reaction: if component[1] not in nameLst: print(str(component[1]) + ' is not in the slop16 database. Please check your spelling and try again. You can use the search function the query the database.') else: comm.append(str(component[0]) + ' ' + component[1]) comm.append('0') comm.append('y') comm.append('n') comm.append(title + '.txt') comm.append('1') comm.append('1') comm.append('empty') threading.Thread(target=self.outLoop2).start() while(self.proc.poll() is None): try: inp = comm[it] it += 1 # inp = bytearray(input('User Input: ')+'\n',sys.stdin.encoding) if(self.proc.poll() is None): self.pin.write(bytearray(inp+'\n',sys.stdin.encoding)) self.pin.flush() except: pass return def calculate_supcrt(self, customFile = None): '''Calculates an output of thermodynamic properties from a SUPCRTBL output file in the same directory. User must input stopping temperature and pressure to allow the program to calculate properly. ''' returnLst = {} max_temp = input('Input the Maximum Temperature') max_press = input('Input the Maximum Pressure') max_temp = float(max_temp) max_press = float(max_press) if customFile != None: file_Path = op.dirname(op.abspath(os.getcwd()))+ '\\' + customFile elif len(self.supcrtFile) ==0: raise ValueError("You haven't run SUPCRT yet") else: filename = self.supcrtFile filePath='/'.join(('resources', filename)) file_Path = pkg_resources.resource_filename(resource_package, filepath) with open(file_Path, 'r') as f: impor = f.read() import_data = impor.replace('\t', ' ') split = import_data.split('\n') for i in range(len(split)): try: if 'REACTION TITLE' in split[i]: returnVar = " ".join(split[i+1].split()).split(' ')[0] elif '************************************ REACTION' in split[i]: returnVar = " ".join(split[i+4].split()).split(' ')[0] except: continue if 'STANDARD STATE PROPERTIES OF THE REACTION AT ELEVATED TEMPERATURES AND PRESSURES' in split[i]: subLst = [] temp = [] pres = [] DH2 = [] lgK = [] dlG = [] dlH = [] dlS = [] dlV = [] dlCp = [] subDict = {} for item in split[(i+7):]: try: if len(item) > 0: subLst = (" ".join(item.split())).split(' ') temp.append(subLst[0]) pres.append(subLst[1]) DH2.append(subLst[2]) lgK.append(subLst[3]) dlG.append(subLst[4]) dlH.append(subLst[5]) dlS.append(subLst[6]) dlV.append(subLst[7]) dlCp.append(subLst[8]) if float(subLst[0]) == max_temp and float(subLst[1]) == max_press: break except: continue subDict['Temperature'] = [float(i) for i in temp] subDict['Pressure'] = [float(i) for i in pres] subDict['DH2O'] = [float(i) for i in DH2] subDict['LogK'] = [float(i) for i in lgK] subDict['delG'] = [float(i) for i in dlG] subDict['delH'] = [float(i) for i in dlH] subDict['delS'] = [float(i) for i in dlS] storeLst = [] for i in dlV: if i =='*********' or i =='NaN': storeLst.append(0) else: storeLst.append(i) subDict['delV'] = storeLst subDict['delCp'] = [float(i) for i in dlCp] returnLst[returnVar] = subDict self.supcrtOut = returnLst def make_supcrt_plots(self): '''Creates plots of LogK and delV for already-calculated SUPCRTBL functions. Produces the same set of plots as the DEW produces''' for i in self.supcrtOut: plt.figure() plt.plot(self.supcrtOut[i]['Temperature'], self.supcrtOut[i]['LogK']) plt.title('LogK vs. Temp for ' + i) plt.xlabel('Temp, Deg C') plt.ylabel('LogK') plt.show() plt.figure() plt.plot(self.supcrtOut[i]['Pressure'], self.supcrtOut[i]['LogK']) plt.title('LogK vs. Pressure for ' + i) plt.ylabel('LogK') plt.xlabel('Pressure (Kb)') plt.show() for i in self.supcrtOut: plt.figure() plt.plot(self.supcrtOut[i]['Temperature'], self.supcrtOut[i]['delG']) plt.title('delV vs. Temp for ' + i) plt.xlabel('Temp, Deg C') plt.ylabel('delG') plt.show() plt.figure() plt.plot(self.supcrtOut[i]['Pressure'], self.supcrtOut[i]['delG']) plt.title('delV vs. Pressure for ' + i) plt.ylabel('delG') plt.xlabel('Pressure (Kb)') plt.show() for i in self.supcrtOut: plt.figure() plt.plot(self.supcrtOut[i]['Temperature'], self.supcrtOut[i]['delV']) plt.title('delV vs. Temp for ' + i) plt.xlabel('Temp, Deg C') plt.ylabel('delV') plt.show() plt.figure() plt.plot(self.supcrtOut[i]['Pressure'], self.supcrtOut[i]['delV']) plt.title('delV vs. Temp for ' + i) plt.ylabel('delV') plt.xlabel('Pressure (Kb)') plt.show()
Instance variables
var DiaArr
-
An array set by the set_TPRho method that contains calculated dielectric constants at temp/pressure used
var DisplayVol
-
Another display volume option. Default to true.
var DisplayVolOpt
-
The option to display volume, default set to true
var ForceSupcrt
-
The option to force supcrt for P < 5 kb. Default is set to true
var GibbsH2O
-
A collection of the gibbs of water values.
var PsatDisplayVol
-
The option to display volume under Psat conditions. Default is set to true.
var QArr
-
An array set by the set_TPRho method that contains calculated Q constants at temp/pressure used
var RhoOfWater
-
The density of water equation input, can be Zheng and Duan 2005, Zheng and Duan 2009, or custom. Default is Z&D 2005
var RhoWatArr
-
An array set by the set_TPRho method that contains calculated water densities at the temperatures and pressures used
var WaterFreeEq
-
The option for the Water free energy equation. Options are D&H 1978, integral, and custom Default is Delaney and Hegelson 1978.
var aqInpGibbs
-
Used for debugging, stores the free energy changes of aqueous inputs
var aqInpV
-
Used for debugging, stores the volume changes of aqueous inputs
var aqOutGibbs
-
Used for debugging, stores the free energy changes of aqueous outputs
var aqOutV
-
Used for debugging, stores the volume changes of aqueous outputs
var aqueousInputs
-
The array of aqueous inputs and multipliers defined by a user
var aqueousOutputs
-
The array of aqueous outputs and multipliers defined by a user
var delG
-
Stores the list of all delG values with temperatures and pressures
var delV
-
Stores the list of all delV values with temperatures and pressures
var densityCollection
-
If custom values are used for the density of water this will store them to be queried by the custom function
var diaEq
-
A variable that stores the number of dielectric constant equation.
var dielectricCollection
-
If custom values are used for the dielectric constant this will store them to be queried by the custom function
var dielectricEq
-
The dielectric equation input. The default is Sverjensky.
var equation
-
A variable that stores the number of the density of water equation. Needs to be renamed
var forceCustom
-
The option to force custom Rho for P< 1 kb. Default is False
var gasInpGibbs
-
Used for debugging, stores the free energy changes of gases
var gasInpV
-
Used for debugging, stores the volume changes of gasseous inputs
var gasInputs
-
The array of gas inputs and multipliers defined by a user
var gasOutGibbs
-
Used for debugging, stores the free energy changes of gasseous inputs
var gasOutV
-
Used for debugging, stores the volume changes of gasseous outputs
var gasOutputs
-
The array of gas outputs and multipliers defined by a user
var gibbsCollection
-
If custom values are used for the gibbs of water this will store them to be queried by the custom function
var gibbsLst
-
A storage variable that lists the gibbs free energy changes. Not sure if necessary
var inAqMat
-
A matrix that stores in aqueous inputs with their properties from the dicitonary inputs
var inGasMat
-
A matrix that stores in gasseous inputs with their properties from the dicitonary inputs
var logK
-
Stores the list of all logK values with temperatures and pressures
var mineralInpGibbs
-
Used for debugging, stores the free energy changes of mineral inputs
var mineralInpV
-
Used for debugging, stores the volume changes of mineral inputs
var mineralInputs
-
The array of mineral inputs and multipliers defined by a user
var mineralOutGibbs
-
Used for debugging, stores the free energy changes of mineral outputs
var mineralOutV
-
Used for debugging, stores the volume changes of mineral outputs
var mineralOutputs
-
The array of mineral outputs and multipliers defined by a user
var outAqMat
-
A matrix that stores in aqueous outputs with their properties from the dicitonary inputs
var outGasMat
-
A matrix that stores in gasseous outputs with their properties from the dicitonary inputs
var pDelG
-
DelG split into arrays with respect to the number of isobars
var pDelV
-
DelV split into arrays with respect to the number of isobars
var pLogK
-
LogK split into arrays with respect to the number of isobars
var pin
-
Needed to run supcrt
var pout
-
Needed to run supcrt
var pressRed
-
Reduced pressure list with no repeats
var pressureUsed
-
An array set by the set_TPRho method that contains all the pressures used for calculation
var proc
-
Needed to run supcrt
var psat
-
A variable that stores the Psat option defined by input
var ptInput
-
The temperature and pressure input, options are Regular, Psat, or custom. Default is regular
var supcrtFile
-
Stores the most recently run SUPCRT file, or none if none have been run
var supcrtOut
-
Stores the output from calculate_supcrt
var tDelG
-
DelG split into arrays with respect to the number of isotherms
var tDelV
-
DelV split into arrays with respect to the number of isotherms
var tKelvin
-
An array set by the set_TPRho method that contains all the temperatures used for calculation in Kelvin
var tLogK
-
LogK split into arrays with respect to the number of isotherms
var tempRed
-
Reduced temperature list with no repeats
var tempUsed
-
An array set by the set_TPRho method that contains all the temperatures used for calculation in celsius
var vLst
-
A storage variable that lists all the volume changes. Not sure if necessary
var waterDensity
-
A variable that stores the number of the density of water equation.
var waterInpGibbs
-
Used for debugging, stores the free energy changes of water outputs
var waterInpV
-
Used for debugging, stores the volume changes of water inputs
var waterInputs
-
An array that defines if water is used in the input and hOw mUcH wAtEr?
var waterOutGibbs
-
Used for debugging, stores the free energy changes of water outputs
var waterOutV
-
Used for debugging, stores the volume changes of water outputs
var waterOutputs
-
An array that defines if water is used in the outputand hOw mUcH wAtEr?
Methods
def calculate(self)
-
The function called that will update all of the parameters. It has no outputs, but allows certain arrays to be queried.
Expand source code
def calculate(self): '''The function called that will update all of the parameters. It has no outputs, but allows certain arrays to be queried. ''' self.calculate_matrices() self.waterInpGibbs, self.waterInpV, self.waterOutGibbs, self.waterOutV = self.calculate_H2O() self.aqInpGibbs, self.aqOutGibbs, self.aqInpV, self.aqOutV = self.calculate_aq() self.gasInpGibbs, self.gasOutGibbs, self.gasInpV, self.gasOutV = self.calculate_gas() G1 = np.delete(np.asarray(self.waterInpGibbs), [0,1]).astype(np.float) * int(self.waterInputs[0][1]) V1 = np.delete(np.asarray(self.waterInpV), [0,1]).astype(np.float) * int(self.waterInputs[0][1]) G4 = np.delete(np.asarray(self.waterOutGibbs), [0,1]).astype(np.float) * int(self.waterOutputs[0][1]) V4 = np.delete(np.asarray(self.waterOutV), [0,1]).astype(np.float) * int(self.waterOutputs[0][1]) # Gas Loops G3, V3 = ([], []) for i in range(len(self.gasInpGibbs)): G3.append(np.multiply(np.delete(np.asarray(self.gasInpGibbs[i]), [0,1]).astype(np.float), int(self.gasInpGibbs[i][1]))) V3.append(np.multiply(np.delete(np.asarray(self.gasInpV[i]), [0,1]).astype(np.float), int(self.gasInpV[i][1]))) G3 = np.sum(G3, axis = 0) V3 = np.sum(V3, axis = 0) G6, V6 = ([], []) for i in range(len(self.gasOutGibbs)): G6.append(np.multiply(np.delete(np.asarray(self.gasOutGibbs[i]), [0,1]).astype(np.float), int(self.gasOutGibbs[i][1]))) V6.append(np.multiply(np.delete(np.asarray(self.gasOutV[i]), [0,1]).astype(np.float), int(self.gasOutV[i][1]))) G6 = np.sum(G6, axis = 0) V6 = np.sum(V6, axis = 0) # Aqueous Inputs G2, V2 = ([], []) for i in range(len(self.aqInpGibbs)): G2.append(np.multiply(np.delete(np.asarray(self.aqInpGibbs[i]), [0,1]).astype(np.float), int(self.aqInpGibbs[i][1]))) V2.append(np.multiply(np.delete(np.asarray(self.aqInpV[i]), [0,1]).astype(np.float), int(self.aqInpV[i][1]))) G2 = np.sum(G2, axis = 0) V2 = np.sum(V2, axis = 0) G5, V5 = ([], []) for i in range(len(self.aqOutGibbs)): G5.append(np.multiply(np.delete(np.asarray(self.aqOutGibbs[i]), [0,1]).astype(np.float), int(self.aqOutGibbs[i][1]))) V5.append(np.multiply(np.delete(np.asarray(self.aqOutV[i]), [0,1]).astype(np.float), int(self.aqOutV[i][1]))) G5 = np.sum(G5, axis = 0) V5 = np.sum(V5, axis = 0) dG = [np.sum([G4, G5, G6], axis = 0) - np.sum([G1, G2, G3], axis = 0)] dV = [np.sum([V4, V5, V6], axis = 0) - np.sum([V1, V2, V3], axis = 0)] # Adding the mineral contributions if they exist, must be at the same temperatures and pressures if len(self.mineralInputs) > 0: for i in range(len(self.mineralInputs)): if self.psat == False: myMinPath = mineralDictionary2 else: myMinPath = mineralDictionary for temp in self.tempUsed: self.mineralInpGibbs.append(np.multiply(myMinPath[self.mineralInputs[i][0]]['delG'][myMinPath[self.mineralInputs[i][0]]['Temperature'].index(temp)], int(self.mineralInputs[i][1]))) self.mineralInpV.append(np.multiply(myMinPath[self.mineralInputs[i][0]]['delV'][myMinPath[self.mineralInputs[i][0]]['Temperature'].index(temp)], int(self.mineralInputs[i][1]))) dG = np.sum([dG, np.sum([self.mineralInpGibbs], axis = 0)], axis = 0) dV = np.sum([dV, np.sum([self.mineralInpV], axis = 0)], axis = 0) if len(self.mineralOutputs) > 0: for i in range(len(self.mineralOutputs)): for temp in self.tempUsed: self.mineralOutGibbs.append(np.multiply(myMinPath[self.mineralOutputs[i][0]]['delG'][myMinPath[self.mineralOutputs[i][0]]['Temperature'].index(temp)], int(self.mineralInputs[i][1]))) self.mineralOutV.append(np.multiply(myMinPath[self.mineralOutputs[i][0]]['delV'][myMinPath[self.mineralOutputs[i][0]]['Temperature'].index(temp)], int(self.mineralInputs[i][1]))) dG = np.sum([dG, -np.sum([self.mineralOutGibbs],axis = 0)], axis = 0) dV = np.sum([dV, -np.sum([self.mineralOutV],axis = 0)], axis = 0) self.logK = [] self.delG = [] self.delV = [] for i in range(len(dG[0])): self.logK.append([-dG[0][i]/(2.302585*self.tKelvin[i]*bigR), self.tempUsed[i], self.pressureUsed[i]]) self.delG.append([dG[0][i], self.tempUsed[i], self.pressureUsed[i]]) self.delV.append([dV[0][i], self.tempUsed[i], self.pressureUsed[i]]) # Sets plotting arrays for convenient plotting of isotherms/isobars if self.ptInput!= 'Psat' or self.psat == False: self.pressRed = list(set(self.pressureUsed)) self.tempRed = list(set(self.tempUsed)) self.pressRed.sort() self.tempRed.sort() temppLogK = defaultdict(list) temppDelG = defaultdict(list) temppDelV = defaultdict(list) temptLogK = defaultdict(list) temptDelG = defaultdict(list) temptDelV = defaultdict(list) for logK, temp, pressure in self.logK: temppLogK[pressure].append(logK) temptLogK[temp].append(logK) for delG, temp, pressure in self.delG: temppDelG[pressure].append(delG) temptDelG[temp].append(delG) for delV, temp, pressure in self.delV: temppDelV[pressure].append(delV) temptDelV[temp].append(delV) for item in temppDelG: self.pDelG.append(temppDelG[item]) for item in temppDelV: self.pDelV.append(temppDelV[item]) for item in temppLogK: self.pLogK.append(temppLogK[item]) for item in temptDelG: self.tDelG.append(temptDelG[item]) for item in temptDelV: self.tDelV.append(temptDelV[item]) for item in temptLogK: self.tLogK.append(temptLogK[item]) return
def calculate_H2O(self)
-
This function requires input and output matrices to be set. This is called within the calculate function.
Expand source code
def calculate_H2O(self): '''This function requires input and output matrices to be set. This is called within the calculate function.''' waterMatInGibbs = [] waterMatOutGibbs = [] waterMatInV = [] waterMatOutV = [] if self.WaterFreeEq == 'D&H 1978': self.waterDensity = 1 elif self.WaterFreeEq == 'Integral': self.waterDensity = 2 else: self.waterDensity = 3 if self.waterInputs[0][0] == 'yes': waterLst = [] waterLst2 = [] waterLst.append('H2O') waterLst.append(self.waterInputs[0][1]) waterLst2.append('H2O') waterLst2.append(self.waterInputs[0][1]) for i in range(len(self.pressureUsed)): #for i in range(len(self.pressureUsed)): if self.WaterFreeEq == 'Custom': try: if self.GibbsH2O[i] == 0: waterLst.append(0) else: waterLst.append(GibbsH2O[i]) except: waterLst.append(GibbsH2O[i]) else: store = DEWEquations.DEWEquations.calculateGibbsOfWater(self.pressureUsed[i], self.tempUsed[i], self.waterDensity, self.equation, self.psat) waterLst.append(store) if self.DisplayVol == True: try: waterLst2.append(18.01528/self.RhoWatArr[i]) except: waterLst2.append(0) continue else: waterLst2.append(0) waterMatInGibbs.append(waterLst) waterMatInV.append(waterLst2) if self.waterOutputs[0][0] =='yes': waterLst = [] waterLst2 = [] waterLst.append('H2O') waterLst.append(self.waterOutputs[0][1]) waterLst2.append('H2O') waterLst2.append(self.waterOutputs[0][1]) for i in range(len(self.pressureUsed)): if self.WaterFreeEq == 'Custom': try: if GibbsH2O[i] == 0: waterLst.append(0) else: waterLst.append(GibbsH2O[i]) except: waterLst.append(GibbsH2O[i]) else: waterLst.append(DEWEquations.DEWEquations.calculateGibbsOfWater(self.pressureUsed[i], self.tempUsed[i], self.waterDensity, self.equation, self.psat)) if self.DisplayVol == True: try: waterLst2.append(18.01528/self.RhoWatArr[i]) except: waterLst2.append(0) else: waterLst2.append(0) waterMatOutGibbs.append(waterLst) waterMatOutV.append(waterLst2) if len(waterMatInGibbs) == 0: waterMatInGibbs = np.zeros((len(self.tKelvin) + 2)) if len(waterMatInV) == 0: waterMatInV = np.zeros((len(self.tKelvin) + 2)) if len(waterMatOutGibbs) == 0: waterMatOutGibbs = np.zeros((len(self.tKelvin) + 2)) if len(waterMatOutV) == 0: waterMatOutV = np.zeros((len(self.tKelvin) + 2)) return waterMatInGibbs, waterMatInV, waterMatOutGibbs, waterMatOutV
def calculate_aq(self)
-
A helper function to calculate the aqueous columns and output them as a matrix. This is called within calculate.
Expand source code
def calculate_aq(self): '''A helper function to calculate the aqueous columns and output them as a matrix. This is called within calculate.''' aqInGibbs = [] aqOuGibbs = [] aqInV = [] aqOuV = [] for aq in self.inAqMat: storelst = [] storelst2= [] storelst.append(aq[0]) storelst.append(aq[15]) storelst2.append(aq[0]) storelst2.append(aq[15]) for i in range(len(self.tKelvin)): storelst.append(aq[2] - aq[4] * (self.tKelvin[i] - T_r) - aq[11] * (self.tKelvin[i] * np.log(self.tKelvin[i]/T_r) - self.tKelvin[i] + T_r) - aq[12]*(10**4)*(((1/(self.tKelvin[i]-Theta)) - (1/(T_r-Theta)))*((Theta-self.tKelvin[i])/(Theta))- (self.tKelvin[i]/(Theta*Theta)) * np.log((T_r*(self.tKelvin[i]-Theta))/(self.tKelvin[i]*(T_r-Theta)))) + aq[7]*(10**-1)*(self.pressureUsed[i]-Pr) + aq[8]*(10**2)*np.log((Psy+self.pressureUsed[i])/(Psy+Pr)) + (1/(self.tKelvin[i]-Theta))*(aq[9]*(self.pressureUsed[i]-Pr) + aq[10]*(10**4)*np.log((Psy+self.pressureUsed[i])/(Psy+Pr))) + DEWEquations.DEWEquations.calculateOmega(self.pressureUsed[i],self.tempUsed[i],self.RhoWatArr[i],aq[0],aq[13]*(10**5),aq[14])*((1/self.DiaArr[i])-1) - aq[13]*(10**5)*((1/E_PrTr)-1) + aq[13]*(10**5)*Upsilon*(self.tKelvin[i]-T_r)) for i in range(len(self.pressureUsed)): storelst2.append((aq[7]/10 + aq[8]*100/(Psy+self.pressureUsed[i]) + (aq[9] + aq[10]*10000/(Psy+self.pressureUsed[i]))/(self.tKelvin[i]-Theta) - DEWEquations.DEWEquations.calculateOmega(self.pressureUsed[i],self.tempUsed[i],self.RhoWatArr[i],aq[0],aq[13]*(10**5),aq[14])*(self.QArr[i]*10**-6 ) + (1/self.DiaArr[i] - 1) * DEWEquations.DEWEquations.calculate_domegadP(self.pressureUsed[i],self.tempUsed[i],self.RhoWatArr[i],aq[0],aq[13]*(10**5),aq[14],self.equation,self.psat))*41.84) aqInGibbs.append(storelst) aqInV.append(storelst2) for aq in self.outAqMat: storelst = [] storelst2= [] storelst.append(aq[0]) storelst.append(aq[15]) storelst2.append(aq[0]) storelst2.append(aq[15]) for i in range(len(self.tKelvin)): storelst.append(aq[2] - aq[4] * (self.tKelvin[i] - T_r) - aq[11] * (self.tKelvin[i] * np.log(self.tKelvin[i]/T_r) - self.tKelvin[i] + T_r) - aq[12]*(10**4)*(((1/(self.tKelvin[i]-Theta)) - (1/(T_r-Theta)))*((Theta-self.tKelvin[i])/(Theta))- (self.tKelvin[i]/(Theta*Theta)) * np.log((T_r*(self.tKelvin[i]-Theta))/(self.tKelvin[i]*(T_r-Theta)))) + aq[7]*(10**-1)*(self.pressureUsed[i]-Pr) + aq[8]*(10**2)*np.log((Psy+self.pressureUsed[i])/(Psy+Pr)) + (1/(self.tKelvin[i]-Theta))*(aq[9]*(self.pressureUsed[i]-Pr) + aq[10]*(10**4)*np.log((Psy+self.pressureUsed[i])/(Psy+Pr))) + DEWEquations.DEWEquations.calculateOmega(self.pressureUsed[i],self.tempUsed[i],self.RhoWatArr[i],aq[0],aq[13]*(10**5),aq[14])*((1/self.DiaArr[i])-1) - aq[13]*(10**5)*((1/E_PrTr)-1) + aq[13]*(10**5)*Upsilon*(self.tKelvin[i]-T_r)) for i in range(len(self.pressureUsed)): storelst2.append((aq[7]/10 + aq[8]*100/(Psy+self.pressureUsed[i]) + (aq[9] + aq[10]*10000/(Psy+self.pressureUsed[i]))/(self.tKelvin[i]-Theta) - DEWEquations.DEWEquations.calculateOmega(self.pressureUsed[i],self.tempUsed[i],self.RhoWatArr[i],aq[0],aq[13]*(10**5),aq[14])*(self.QArr[i]*10**-6 ) + (1/self.DiaArr[i] - 1) * DEWEquations.DEWEquations.calculate_domegadP(self.pressureUsed[i],self.tempUsed[i],self.RhoWatArr[i],aq[0],aq[13]*(10**5),aq[14],self.equation,self.psat))*41.84) aqOuGibbs.append(storelst) aqOuV.append(storelst2) if len(aqInGibbs) == 0: aqInGibbs = [np.zeros(len(self.tKelvin) + 2)] if len(aqOuGibbs) == 0: aqOuGibbs = [np.zeros(len(self.tKelvin) + 2)] if len(aqInV) == 0: aqInV = [np.zeros(len(self.tKelvin) + 2)] if len(aqOuV) == 0: aqOuV = [np.zeros(len(self.tKelvin) + 2)] return aqInGibbs, aqOuGibbs, aqInV, aqOuV
def calculate_gas(self)
-
A helper function to calculate the gasseous columns and output them as a matrix. Specifically returns the arrays gasInGibbs, gasOutGibbs, gasInV, gasOuV. Needs self.tempUsed and self.tKelvin to be set, as well as the input gas matrix. It is called within the calculate function.
Expand source code
def calculate_gas(self): '''A helper function to calculate the gasseous columns and output them as a matrix. Specifically returns the arrays gasInGibbs, gasOutGibbs, gasInV, gasOuV. Needs self.tempUsed and self.tKelvin to be set, as well as the input gas matrix. It is called within the calculate function.''' gasInGibbs = [] gasOuGibbs = [] gasInV = [] gasOuV = [] for gas in self.inGasMat: storelst = [] storelst2 =[] storelst.append(gas[0]) storelst.append(gas[10]) storelst2.append(gas[0]) storelst2.append(gas[10]) for i in range(len(self.tempUsed)): if self.DisplayVol == False or self.tempUsed[i] == 0: storelst2.append(0) else: storelst2.append(24.465) for i in range(len(self.tKelvin)): storelst.append(gas[2] - gas[4]*(self.tKelvin[i]-T_r) + gas[6]*(self.tKelvin[i]-T_r - self.tKelvin[i]*np.log(self.tKelvin[i]/T_r)) + gas[7]*(0.001)/2*(2*self.tKelvin[i]*T_r -np.double(self.tKelvin[i])**2 - np.double(T_r) **2) + gas[8]*100000*(np.double(self.tKelvin[i])**2 + np.double(T_r)**2 -2*self.tKelvin[i]*T_r)/(2*self.tKelvin[i]*np.double(T_r)**2)) gasInGibbs.append(storelst) gasInV.append(storelst2) for gas in self.outGasMat: storelst = [] storelst2 = [] storelst.append(gas[0]) storelst.append(gas[10]) storelst2.append(gas[0]) storelst2.append(gas[10]) for i in range(len(self.tempUsed)): if self.DisplayVol == False or self.tempUsed[i] == 0: storelst2.append(0) else: storelst2.append(24.465) for i in range(len(self.tKelvin)): storelst.append(gas[2] - gas[4]*(self.tKelvin[i]-T_r) + gas[6]*(self.tKelvin[i]-T_r - self.tKelvin[i]*np.log(self.tKelvin[i]/T_r)) + gas[7]*(0.001)/2*(2*self.tKelvin[i]*T_r -np.double(self.tKelvin[i])**2 - np.double(T_r) **2) + gas[8]*100000*(np.double(self.tKelvin[i])**2 + np.double(T_r)**2 -2*self.tKelvin[i]*T_r)/(2*self.tKelvin[i]*np.double(T_r)**2)) gasOuGibbs.append(storelst) gasOuV.append(storelst2) if len(gasInGibbs) == 0: gasInGibbs = [np.zeros(len(self.tKelvin) + 2)] if len(gasOuGibbs) == 0: gasOuGibbs = [np.zeros(len(self.tKelvin) + 2)] if len(gasInV) == 0: gasInV = [np.zeros(len(self.tKelvin) + 2)] if len(gasOuV) == 0: gasOuV = [np.zeros(len(self.tKelvin) + 2)] return gasInGibbs, gasOuGibbs, gasInV, gasOuV
def calculate_matrices(self)
-
A helper function to aggregate the values to the input and output matrices. It requires both the input and output arrays to be set up to function. It is called within "calculate"
Expand source code
def calculate_matrices(self): '''A helper function to aggregate the values to the input and output matrices. It requires both the input and output arrays to be set up to function. It is called within "calculate"''' self.inAqMat = [] self.inGasMat = [] self.outAqMat = [] self.outGasMat = [] for i in self.aqueousInputs: self.inAqMat.append([i[0],symbolDict[i[0]], delGf[i[0]], delHf[i[0]], entropy[i[0]],volume[i[0]],specHeat[i[0]], a1x10[i[0]], a2x10_2[i[0]], a3[i[0]],a4x10_4[i[0]],c1[i[0]],c2x10_4[i[0]],omegax10_5[i[0]],Z[i[0]], i[1]]) for i in self.gasInputs: self.inGasMat.append([i[0],GasSymb[i[0]],GasDelGf[i[0]],GasDelHf[i[0]],GasEntropy[i[0]],GasCp[i[0]], GasA[i[0]], GasBx103[i[0]],GasCx10_5[i[0]],GasT[i[0]], i[1]]) for i in self.aqueousOutputs: self.outAqMat.append([i[0],symbolDict[i[0]], delGf[i[0]], delHf[i[0]], entropy[i[0]],volume[i[0]],specHeat[i[0]], a1x10[i[0]], a2x10_2[i[0]], a3[i[0]],a4x10_4[i[0]],c1[i[0]],c2x10_4[i[0]],omegax10_5[i[0]],Z[i[0]], i[1]]) for i in self.gasOutputs: self.outGasMat.append([i[0],GasSymb[i[0]],GasDelGf[i[0]],GasDelHf[i[0]],GasEntropy[i[0]],GasCp[i[0]], GasA[i[0]], GasBx103[i[0]],GasCx10_5[i[0]],GasT[i[0]],i[1]]) return
def calculate_supcrt(self, customFile=None)
-
Calculates an output of thermodynamic properties from a SUPCRTBL output file in the same directory. User must input stopping temperature and pressure to allow the program to calculate properly.
Expand source code
def calculate_supcrt(self, customFile = None): '''Calculates an output of thermodynamic properties from a SUPCRTBL output file in the same directory. User must input stopping temperature and pressure to allow the program to calculate properly. ''' returnLst = {} max_temp = input('Input the Maximum Temperature') max_press = input('Input the Maximum Pressure') max_temp = float(max_temp) max_press = float(max_press) if customFile != None: file_Path = op.dirname(op.abspath(os.getcwd()))+ '\\' + customFile elif len(self.supcrtFile) ==0: raise ValueError(#34;You haven't run SUPCRT yet") else: filename = self.supcrtFile filePath='/'.join(('resources', filename)) file_Path = pkg_resources.resource_filename(resource_package, filepath) with open(file_Path, 'r') as f: impor = f.read() import_data = impor.replace('\t', ' ') split = import_data.split('\n') for i in range(len(split)): try: if 'REACTION TITLE' in split[i]: returnVar = " ".join(split[i+1].split()).split(' ')[0] elif '************************************ REACTION' in split[i]: returnVar = " ".join(split[i+4].split()).split(' ')[0] except: continue if 'STANDARD STATE PROPERTIES OF THE REACTION AT ELEVATED TEMPERATURES AND PRESSURES' in split[i]: subLst = [] temp = [] pres = [] DH2 = [] lgK = [] dlG = [] dlH = [] dlS = [] dlV = [] dlCp = [] subDict = {} for item in split[(i+7):]: try: if len(item) > 0: subLst = (" ".join(item.split())).split(' ') temp.append(subLst[0]) pres.append(subLst[1]) DH2.append(subLst[2]) lgK.append(subLst[3]) dlG.append(subLst[4]) dlH.append(subLst[5]) dlS.append(subLst[6]) dlV.append(subLst[7]) dlCp.append(subLst[8]) if float(subLst[0]) == max_temp and float(subLst[1]) == max_press: break except: continue subDict['Temperature'] = [float(i) for i in temp] subDict['Pressure'] = [float(i) for i in pres] subDict['DH2O'] = [float(i) for i in DH2] subDict['LogK'] = [float(i) for i in lgK] subDict['delG'] = [float(i) for i in dlG] subDict['delH'] = [float(i) for i in dlH] subDict['delS'] = [float(i) for i in dlS] storeLst = [] for i in dlV: if i =='*********' or i =='NaN': storeLst.append(0) else: storeLst.append(i) subDict['delV'] = storeLst subDict['delCp'] = [float(i) for i in dlCp] returnLst[returnVar] = subDict self.supcrtOut = returnLst
def calculate_supcrt_special(self, customFile=None)
-
Calculates the output from either SUPCRTBL/SUPCRT96 at isothermal/isobaric temperatures
Expand source code
def calculate_supcrt_special(self, customFile = None): '''Calculates the output from either SUPCRTBL/SUPCRT96 at isothermal/isobaric temperatures''' returnLst = {} if customFile != None: filename = op.dirname(op.abspath(os.getcwd()))+ '\\' + customFile elif len(self.supcrtFile) ==0: raise ValueError("You haven't run SUPCRT yet") else: filename = self.supcrtFile with open(filename, 'r') as f: impor = f.read() import_data = impor.replace('\t', ' ') split = import_data.split('\n') for i in range(len(split)): try: if 'ISOTHERMS(degC)' in split[i]: finalTemp = " ".join(split[i].split()).split(' ')[5] finalPress = " ".join(split[i+1].split()).split(' ')[6] returnVar = input('Enter reaction title') except: continue if 'STANDARD STATE PROPERTIES OF THE REACTION AT ELEVATED TEMPERATURES AND PRESSURES' in split[i]: subLst = [] temp = [] pres = [] DH2 = [] lgK = [] dlG = [] dlH = [] dlS = [] dlV = [] dlCp = [] subDict = {} for item in split[(i+4):]: if len(item) > 0: subLst = (" ".join(item.split())).split(' ') try: float(subLst[0]) except: continue try: a = subLst[0] b = subLst[1] c = subLst[2] d = subLst[3] e = subLst[4] f = subLst[5] g = subLst[6] h = subLst[7] i = subLst[8] temp.append(a) pres.append(b) DH2.append(c) lgK.append(d) dlG.append(e) dlH.append(f) dlS.append(g) dlV.append(h) dlCp.append(i) if float(subLst[0]) == finalTemp and float(subLst[1]) == finalPress: break except: continue subDict['Temperature'] = [float(i) for i in temp] subDict['Pressure'] = [float(i) for i in pres] DH2Lst = [] lgKLst = [] dlGLst = [] dlHLst = [] dlSLst = [] dlVLst = [] dlCpLst = [] for i in range(len(DH2)): try: DH2Lst.append(float(DH2[i])) except: DH2Lst.append(0) try: lgKLst.append(float(lgK[i])) except: lgKLst.append(0) try: dlGLst.append(float(dlG[i])) except: dlGLst.append(0) try: dlHLst.append(float(dlH[i])) except: dlHLst.append(0) try: dlSLst.append(float(dlS[i])) except: dlSLst.append(0) try: dlVLst.append(float(dlV[i])) except: dlVLst.append(0) try: dlCpLst.append(dlCp[i]) except: dlCpLst.append[0] subDict['DH2O'] = DH2Lst subDict['LogK'] = lgKLst subDict['delG'] = dlGLst subDict['delH'] = dlHLst subDict['delS'] = dlSLst subDict['delV'] = dlVLst subDict['delCp'] = dlCpLst returnLst[returnVar] = subDict self.supcrtOut = returnLst
def clear(self)
-
Clears variables
Expand source code
def clear(self): '''Clears variables''' self.__init__() return
def export_to_csv(self)
-
Expand source code
def export_to_csv(self): dV = [row[0] for row in self.delV] dG = [row[0] for row in self.delG] lK = [row[0] for row in self.logK] T = [row[1] for row in self.logK] P = [row[2] for row in self.logK] output_array = np.column_stack([T,P, dV,dG,lK]) df = pd.DataFrame(output_array) df.columns = ['Temperature','Pressure','delV','delG','LogK'] name = input('Input the name of the CSV file') finalName = name + ".csv" df.to_csv(finalName, index = False)
def import_custom_sheets(self)
-
A helper function to import custom data from the Deep Earth Water Model. This only currently works for an unmodified Deep Earth Water Model Sheet format (6_23_20). This is not dependent on anything else being called first.
Expand source code
def import_custom_sheets(self): '''A helper function to import custom data from the Deep Earth Water Model. This only currently works for an unmodified Deep Earth Water Model Sheet format (6_23_20). This is not dependent on anything else being called first.''' diaL = pd.read_csv(diePath, header = None) dia = diaL.to_numpy() dia = dia[4:, 1:] diaTrim = dia[1:, 1:] diaCollection = [] for row in range(len(diaTrim)): for pressure in range(len(diaTrim[0])): # in form pressure, temperature, value diaCollection.append([dia[0][pressure + 1], dia[row + 1][0], diaTrim[row][pressure]]) watDen = pd.read_csv(denPath, header = None) w = watDen.to_numpy() w = w[4:, 1:] wTrim = w[1:,1:] watDenCollection = [] for row in range(len(wTrim)): for pressure in range(len(wTrim[0])): # in form pressure, temperature, value watDenCollection.append([w[0][pressure + 1], w[row + 1][0], wTrim[row][pressure]]) gibbsOfWater = pd.read_csv(gPath, header = None) gibbs = gibbsOfWater.to_numpy() gibbs = gibbs[3:,:] gibbsTrim = gibbs[1:, 1:] gibbsCollection = [] for row in range(len(gibbsTrim)): for pressure in range(len(gibbsTrim[0])): # in form pressure, temperature, value gibbsCollection.append([gibbs[0][pressure + 1], gibbs[row + 1][0], gibbsTrim[row][pressure]]) return diaCollection, watDenCollection, gibbsCollection
def make_plots(self)
-
A final function that the user calls to make the plots possible in the Excel spreadsheet.
Expand source code
def make_plots(self): '''A final function that the user calls to make the plots possible in the Excel spreadsheet. ''' plt.clf() ###### PSAT PLOTS ####### if self.psat == True or self.ptInput =='Psat': plt.figure() plt.plot(self.pressureUsed, [i[0] for i in self.logK]) plt.xlabel('Pressure (bar)') plt.ylabel('LogK') plt.title('Pressure vs. LogK Psat Curve') plt.show() plt.figure() plt.plot(self.pressureUsed, [i[0] for i in self.delG]) plt.xlabel('Pressure (bar)') plt.ylabel(r'$\Delta$G') plt.title('Pressure vs. $\Delta$G Psat Curve') plt.show() plt.figure() plt.plot(self.pressureUsed, [i[0] for i in self.delV]) plt.xlabel('Pressure (bar)') plt.ylabel('$\Delta$V') plt.title('Pressure vs. $\Delta$V Psat Curve') plt.show() plt.figure() plt.plot(self.tempUsed, [i[0] for i in self.logK]) plt.xlabel(r'Temperature ($^\circ$ C)') plt.ylabel('LogK') plt.title('Temperature vs. LogK Psat Curve') plt.show() plt.figure() plt.plot(self.tempUsed, [i[0] for i in self.delG]) plt.xlabel('Temperature ($^\circ$ C)') plt.ylabel('$\Delta$G') plt.title('Temperature vs. $\Delta$G Psat Curve') plt.show() plt.figure() plt.plot(self.tempUsed, [i[0] for i in self.delV]) plt.xlabel('Temperature ($^\circ$ C)') plt.ylabel('$\Delta$V') plt.title('Temperature vs. $\Delta$V Psat Curve') plt.show() ####### NON PSAT PLOTS ######## else: # T Plots plt.figure() for i in self.pDelG: plt.plot(self.tempRed, i) plt.legend(self.pressRed,bbox_to_anchor=(1.05, 1), title = 'Pressure (bar)', loc='upper left') plt.xlabel('Temperature ($^\circ$C)') plt.ylabel('$\Delta$G') plt.title('Temperature vs. $\Delta$G') plt.show() plt.figure() for i in self.pDelV: plt.plot(self.tempRed, i) plt.legend(self.pressRed,bbox_to_anchor=(1.05, 1), title = 'Pressure (bar)', loc='upper left') plt.xlabel('Temperature ($^\circ$C)') plt.ylabel('$\Delta$V') plt.title('Temperature vs. $\Delta$V') plt.show() plt.figure() for i in self.pLogK: plt.plot(self.tempRed, i) plt.legend(self.pressRed,bbox_to_anchor=(1.05, 1), title = 'Pressure (bar)', loc='upper left') plt.xlabel('Temperature ($^\circ$C)') plt.ylabel('LogK') plt.title('Temperature vs. LogK') plt.show() # P Plots plt.figure() for i in self.tDelG: plt.plot(self.pressRed, i) plt.legend(self.tempRed,bbox_to_anchor=(1.05, 1), title = 'Temperature ($^\circ$C)', loc='upper left') plt.xlabel('Pressure (bar)') plt.ylabel('$\Delta$G') plt.title('Pressure vs. $\Delta$G') plt.show() plt.figure() for i in self.tDelV: plt.plot(self.pressRed, i) plt.legend(self.tempRed,bbox_to_anchor=(1.05, 1), title = 'Temperature ($^\circ$C)', loc='upper left') plt.xlabel('Pressure (bar)') plt.ylabel('$\Delta$V') plt.title('Pressure vs. $\Delta$V') plt.show() plt.figure() for i in self.tLogK: plt.plot(self.pressRed, i) plt.legend(self.tempRed,bbox_to_anchor=(1.05, 1), title = 'Temperature ($^\circ$C)', loc='upper left') plt.xlabel('Pressure (bar)') plt.ylabel('LogK') plt.title('Pressure vs. LogK') plt.show() return
def make_supcrt_plots(self)
-
Creates plots of LogK and delV for already-calculated SUPCRTBL functions. Produces the same set of plots as the DEW produces
Expand source code
def make_supcrt_plots(self): '''Creates plots of LogK and delV for already-calculated SUPCRTBL functions. Produces the same set of plots as the DEW produces''' for i in self.supcrtOut: plt.figure() plt.plot(self.supcrtOut[i]['Temperature'], self.supcrtOut[i]['LogK']) plt.title('LogK vs. Temp for ' + i) plt.xlabel('Temp, Deg C') plt.ylabel('LogK') plt.show() plt.figure() plt.plot(self.supcrtOut[i]['Pressure'], self.supcrtOut[i]['LogK']) plt.title('LogK vs. Pressure for ' + i) plt.ylabel('LogK') plt.xlabel('Pressure (Kb)') plt.show() for i in self.supcrtOut: plt.figure() plt.plot(self.supcrtOut[i]['Temperature'], self.supcrtOut[i]['delG']) plt.title('delV vs. Temp for ' + i) plt.xlabel('Temp, Deg C') plt.ylabel('delG') plt.show() plt.figure() plt.plot(self.supcrtOut[i]['Pressure'], self.supcrtOut[i]['delG']) plt.title('delV vs. Pressure for ' + i) plt.ylabel('delG') plt.xlabel('Pressure (Kb)') plt.show() for i in self.supcrtOut: plt.figure() plt.plot(self.supcrtOut[i]['Temperature'], self.supcrtOut[i]['delV']) plt.title('delV vs. Temp for ' + i) plt.xlabel('Temp, Deg C') plt.ylabel('delV') plt.show() plt.figure() plt.plot(self.supcrtOut[i]['Pressure'], self.supcrtOut[i]['delV']) plt.title('delV vs. Temp for ' + i) plt.ylabel('delV') plt.xlabel('Pressure (Kb)') plt.show()
def options(self)
-
Expand source code
def options(self): print('Welcome to DEWPython, here are the options you can run:') print('1. DEW(): this initializes a Deep Earth Water Model Object') print(' -The DEW object requires the set_inputs, set_outputs, set_TPRho, and calculate methods to be run.') print(' -You can also utilize the import_custom_sheets method to import custom CSV data') print(' -After calculating you can use the make_plots or export_to_csv methods.') print('2. run_supcrt: this initializes an inline run of SUPCRTBL') print(' -After initializing the SUPCRTBL object, run calculate_supcrt to store the supcrt outputs in arrays') print(' -You can also use run_supcrt on a supcrt ouput file that has already been run by adding the optional argument of the file name') print(' -After this you can run make_supcrt_plots to plot the supcrt files akin the a DEW file')
def outLoop(self)
-
A helper function to allow SUPCRTBL to run
Expand source code
def outLoop(self): '''A helper function to allow SUPCRTBL to run''' running = True while(running): line = self.pout.readline().decode(sys.stdout.encoding) print(line, end='') running='\n' in line print('Finished')
def outLoop2(self)
-
A helper function to allow SUPCRT96 to run
Expand source code
def outLoop2(self): '''A helper function to allow SUPCRT96 to run''' running = True while(running): line = self.pout.readline().decode(sys.stdout.encoding) running='\n' in line
def run(self, pt_arr, min_inp=[], aq_inp=[], g_inp=[], h2o_inp=0, min_out=[], aq_out=[], g_out=[], h2o_out=0, ptInp='Psat', rhoWat='Z&D 2005', forceBool=False, dieEQ='Supcrt', forceSC=True, WFEQ='D&H 1978', dsV=True, pdsV=True, DV=True, EQ=1, dEQ=1, pst=True, mWn=1, makeP=False)
-
Expand source code
def run(self, pt_arr, min_inp =[], aq_inp = [], g_inp = [], h2o_inp = 0, min_out = [],aq_out =[], g_out = [],h2o_out = 0, ptInp = 'Psat', rhoWat = 'Z&D 2005', forceBool = False, dieEQ = 'Supcrt', forceSC = True, WFEQ ='D&H 1978', dsV = True, pdsV = True, DV = True, EQ = 1, dEQ = 1, pst = True, mWn = 1, makeP = False): if h2o_inp > 0: self.waterInputs = [['yes',h2o_inp]] else: self.waterInputs = [['no',0]] if h2o_out > 0: self.waterOutputs = [['yes',h2o_out]] else: self.waterOutputs = [['no',0]] self.mineralInputs = min_inp self.aqueousInputs = aq_inp self.gasInputs = g_inp self.mineralOutputs = min_out self.aqueousOutputs = aq_out self.gasOutputs = g_out self.ptInput = ptInp self.RhoOfWater = rhoWat self.forceCustom = forceBool self.dielectricEq = dieEQ self.ForceSupcrt = forceSC self.WaterFreeEq = WFEQ self.DisplayVolOpt = dsV self.PsatDisplayVol = pdsV self.DisplayVol = DV self.equation = EQ self.diaEq = dEQ self.psat = pst self.waterDensity = mWn # to actually run: self.set_tp(pt_arr) self.calculate() if makeP == True: self.make_plots() return
def run_supcrt(self, version='96')
-
A function that runs the pre-compiled SUPCRTBL found in the file folder
Expand source code
def run_supcrt(self, version = '96'): '''A function that runs the pre-compiled SUPCRTBL found in the file folder''' if version != '96': sup_path = '/'.join(('resources', 'SUPCRTBL.exe')) supPath = pkg_resources.resource_filename(resource_package, sup_path) else: sup_path = '/'.join(('resources', 'supcrt96.exe')) supPath = pkg_resources.resource_filename(resource_package, sup_path) self.proc = subprocess.Popen(supPath,shell = True, stdout = subprocess.PIPE, stdin = subprocess.PIPE, stderr = subprocess.STDOUT) self.pout = self.proc.stdout self.pin = self.proc.stdin threading.Thread(target=self.outLoop).start() while(self.proc.poll() is None): var = input('User Input: ') if '.txt' in var: self.supcrtFile = op.dirname(op.abspath(__file__)) + '\\resources\\' + var inp=bytearray(var +'\n', sys.stdin.encoding) if(self.proc.poll() is None): self.pin.write(inp) self.pin.flush() return
def set_TPRho(self)
-
Sets arrays of temperature, pressure, water density, and Q to be used in the model based on user input. Requires that the input and output arrays have been set up otherwise it will return a divide by 0 error in the calculations.
Expand source code
def set_TPRho(self): '''Sets arrays of temperature, pressure, water density, and Q to be used in the model based on user input. Requires that the input and output arrays have been set up otherwise it will return a divide by 0 error in the calculations.''' pressArr = [] tempArr = [] self.RhoWatArr = [] self.DiaArr = [] self.QArr =[] self.gibbsLst = [] self.logK = [] self.vLst = [] self.delG = [] self.delV = [] if self.ptInput == "Custom": ptSheet = pd.read_csv(inpPath,encoding= 'unicode_escape', header = None) ptFinder = ptSheet.to_numpy() tempArr = [float(i[1]) for i in ptFinder[4:]] pressArr = [float(i[0]) for i in ptFinder[4:]] elif self.ptInput == "Regular": validBool = False while not validBool: try: templow = int(input('Input the minimum temperature')) temphigh = int(input('Input the maximum temperature')) tempstep = int(input('Input the temperature step')) pmin = float(input('Input the minimum pressure (Kb)')) pmax = float(input('Input the maximum pressure (Kb)')) pstep = float(input('Input the pressure step (Kb)')) validBool = True except ValueError: print('You have entered a non-integer value, please start again') tempArr = np.arange(start= templow, stop = temphigh + .00001, step = tempstep) parrHelp = np.arange(start= pmin, stop = pmax + .00001, step = pstep) for i in range(len(parrHelp)): pressArr.append([parrHelp[i]]* len(tempArr)) pressArr = np.multiply(pressArr, 1000) tempArr = [tempArr] * len(parrHelp) elif self.ptInput == "Psat": validBool = False while not validBool: try: templow = int(input('Input the minimum temperature')) temphigh = int(input('Input the mamximum temperature')) tempstep = int(input('Input the temperature step')) validBool = True except ValueError: print('You have entered a non-integer value, please start again') tempArr = np.arange(start= templow, stop = temphigh + 1, step = tempstep) for i in range(len(tempArr)): if tempArr[i] < 100: pressArr.append(1) else: pressArr.append(2.1650906415E-11*np.double(tempArr[i])**5 + 0.0008467019353*np.double(tempArr[i])**2 - 0.17973651666*tempArr[i] + 10.7768850763807) else: # If I've done the checking correctly above it should never reach this raise ValueError("You have not set your options yet, please set them before continuing") self.tempUsed = np.ndarray.flatten(np.asarray(tempArr)) self.pressureUsed = np.ndarray.flatten(np.asarray(pressArr)) self.tKelvin = np.add(self.tempUsed, 273.15) # code to set options in a way the equations can understand if self.ptInput == "Psat": self.psat = True else: self.psat = False if self.RhoOfWater =='Z&D 2005': self.equation = 1 elif self.RhoOfWater == 'Z&D 2009': self.equation = 2 else: self.equation = 3 if self.dielectricEq == "Supcrt": self.diaEq = 1 elif self.dielectricEq == "Franck": self.diaEq = 2 elif self.dielectricEq == "Fernandez": self.diaEq = 3 elif self.dielectricEq == "Sverjensky": self.diaEq = 4 else: self.diaEq = 5 # write code to take in custom Rho, G, and Water Values here self.densityCollection = np.asarray(self.densityCollection).astype(float) self.dielectricCollection = np.asarray(self.dielectricCollection).astype(float) self.gibbsCollection = np.asarray(self.gibbsCollection).astype(float) # Sets the water density array for i in range(len(self.pressureUsed)): # For the custom array if self.RhoOfWater =="Custom" or (self.forceCustom == True and self.pressureUsed[i] < 1000): idx = np.intersect1d(np.where(np.asarray(self.densityCollection) == self.pressureUsed[i]/1000), np.where(np.asarray(self.densityCollection) == self.tempUsed[i]))[0] if not np.isnan(self.densityCollection[idx][2]): self.RhoWatArr.append(self.densityCollection[idx][2]) else: self.RhoWatArr.append(0) else: self.RhoWatArr.append(DEWEquations.DEWEquations.calculateDensity(self.pressureUsed[i], self.tempUsed[i], self.equation, 0.01, self.psat)) # Sets the dielectric constant array for i in range(len(self.pressureUsed)): # for the custom array if self.dielectricEq == "Custom": idx = np.intersect1d(np.where(np.asarray(self.dielectricCollection) == self.pressureUsed[i]/1000), np.where(np.asarray(self.dielectricCollection) == self.tempUsed[i]))[0] if not np.isnan(self.dielectricCollection[idx][2]): self.DiaArr.append(self.dielectricCollection[idx][2]) else: self.DiaArr.append(0) else: if self.ForceSupcrt == True and self.pressureUsed[i] < 5000 and self.psat == False: self.DiaArr.append(DEWEquations.DEWEquations.calculateEpsilon(self.RhoWatArr[i], self.tempUsed[i], 1, self.psat)) else: self.DiaArr.append(DEWEquations.DEWEquations.calculateEpsilon(self.RhoWatArr[i], self.tempUsed[i], self.diaEq, self.psat)) ### The function works up until this point, I haven't debugged further yet (6_29_20) ### # Sets up the Q array for i in range(len(self.pressureUsed)): if self.DisplayVol == True: try: # Has issues with some Q, not sure if problematic self.QArr.append(float(DEWEquations.DEWEquations.calculateQ(self.pressureUsed[i], self.tempUsed[i], self.RhoWatArr[i], self.equation, self.diaEq, self.psat))*np.double(10)**6) except: self.QArr.append(0) else: self.QArr.append(0) # Sets up custom Gibbs of Water Array: if self.WaterFreeEq == "Custom": for i in range(len(self.pressureUsed)): idx = np.intersect1d(np.where(np.asarray(self.gibbsCollection) == self.pressureUsed[i]/1000), np.where(np.asarray(self.gibbsCollection) == self.tempUsed[i]))[0] if not np.isnan(self.gibbsCollection[idx][2]): self.GibbsH2O.append(self.gibbsCollection[idx][2]) else: self.GibbsH2O.append(0) return
def set_inputs(self)
-
Call this to set the input Arrays. This is not dependent on anything else being called first.
Expand source code
def set_inputs(self): '''Call this to set the input Arrays. This is not dependent on anything else being called first.''' # A list of integers intLst = ['1','2','3','4', '5', '6','7', '8', '9', '10', '11'] # Mineral Loop mineralCount = 0 aqCount = 0 gasCount = 0 self.mineralInputs = [] self.aqueousInputs = [] self.gasInputs = [] self.waterInputs = [] while mineralCount < 15: mineralCount += 1 validBool = False while not validBool: inp = input('Input Mineral Species') # can insert mineral validation here if possible if inp in mineralDictionary: validBool = True elif inp == "": validBool = True else: print('Your Species is not in the list, please check your spelling') continue validBool2 = False while not validBool2: inp2 = input('Input Mineral Species Multiplier') if inp2 in intLst: validBool2 = True elif inp == "": validBool2 = True else: print('Your multiplier is invalid, please check to make sure this is an integer') if inp == "": break self.mineralInputs.append([inp, inp2]) while aqCount <15: aqCount += 1 validBool = False while not validBool: inp = input('Input Aqueous Species') if inp in nameLst: validBool = True elif inp == "": validBool = True else: print('Your Species is not in the list, please check your spelling') continue validBool2 = False if validBool: while not validBool2: inp2 = input('Input Aqueous Species Multiplier') if inp2 in intLst: validBool2 = True elif inp == "": validBool2 = True else: print('Your multiplier is invalid, please check to make sure this is an integer') if inp == "": break self.aqueousInputs.append([inp, inp2]) while gasCount < 15: gasCount += 1 validBool = False while not validBool: inp = input('Input Gas Species') if inp in GasLst: validBool = True elif inp == "": validBool = True else: print('Your Species is not in the list, please check your spelling') continue if validBool: validBool2 = False while not validBool2: inp2 = input('Input Gas Species Multiplier') if inp2 in intLst: validBool2 = True elif inp == "": validBool2 = True else: print('Your multiplier is invalid, please check to make sure this is an integer') if inp == "": break self.gasInputs.append([inp, inp2]) # Water validBool3 = False while not validBool3: inpWater = input('Would you like to use water? (yes/no)') if inpWater in ['yes', 'no']: validBool3 = True else: print('Please answer yes or no') continue if inpWater == 'yes': validBool3 = False while not validBool3: m3 = input('Enter enter water Multiplier') if m3 in intLst: validBool3 = True else: print('Please enter a valid integer multiplier ') else: m3 = 0 self.waterInputs.append([inpWater, m3]) return
def set_outputs(self)
-
Call this to set the output Arrays. This is not dependent on anything else being called first.
Expand source code
def set_outputs(self): '''Call this to set the output Arrays. This is not dependent on anything else being called first.''' # A list of integers intLst = ['1','2','3','4', '5', '6','7', '8', '9', '10', '11'] # Mineral Loop mineralCount = 0 aqCount = 0 gasCount = 0 self.mineralOutputs = [] self.aqueousOutputs = [] self.gasOutputs = [] self.waterOutputs = [] while mineralCount < 15: mineralCount += 1 validBool = False while not validBool: inp = input('Output Mineral Species') # can insert mineral validation here if possible validBool = True validBool2 = False while not validBool2: inp2 = input('Output Mineral Species Multiplier') if inp2 in intLst: validBool2 = True elif inp == "": validBool2 = True else: print('Your multiplier is invalid, please check to make sure this is an integer') if inp == "": break self.mineralOutputs.append([inp, inp2]) while aqCount <15: aqCount += 1 validBool = False while not validBool: inp = input('Output Aqueous Species') if inp in nameLst: validBool = True elif inp == "": validBool = True else: print('Your Species is not in the list, please check your spelling') continue validBool2 = False if validBool: while not validBool2: inp2 = input('Output Aqueous Species Multiplier') if inp2 in intLst: validBool2 = True elif inp == "": validBool2 = True else: print('Your multiplier is invalid, please check to make sure this is an integer') if inp == "": break self.aqueousOutputs.append([inp, inp2]) while gasCount < 15: gasCount += 1 validBool = False while not validBool: inp = input('Input Gas Species') if inp in GasLst: validBool = True elif inp == "": validBool = True else: print('Your Species is not in the list, please check your spelling') continue validBool2 = False if validBool: while not validBool2: inp2 = input('Input Gas Species Multiplier') if inp2 in intLst: validBool2 = True elif inp == "": validBool2 = True else: print('Your multiplier is invalid, please check to make sure fthis is an integer') if inp == "": break self.gasOutputs.append([inp, inp2]) # Water validBool3 = False while not validBool3: outWater = input('Would you like to use water in the output? (yes/no)') if outWater in ['yes', 'no']: validBool3 = True else: print('Please answer yes or no') if outWater == 'yes': validBool3 = False while not validBool3: m3 = input('Enter enter water Multiplier') if m3 in intLst: validBool3 = True else: print('Please enter a valid integer multiplier ') else: m3 = 0 self.waterOutputs.append([outWater, m3]) return
def set_preferences(self)
-
A function that prompts for user inputs. This is not dependent on anything else being called first. Defaults are set to be identical to the example calculation on the Deep Earth Water Model Excel Sheet.
Expand source code
def set_preferences(self): '''A function that prompts for user inputs. This is not dependent on anything else being called first. Defaults are set to be identical to the example calculation on the Deep Earth Water Model Excel Sheet.''' validBool = False while not validBool: ptInp = input('Which P-T input would you like to use? "Custom", "Regular", or "Psat"') if ptInp in ['Custom', 'Regular', 'Psat']: validBool = True self.ptInput = ptInp else: print('Please enter one of the provided options') validBool = False while not validBool: RhoOfwater = input('Which density of water would you like to use? "Z&D 2005", "Z&D 2009", or "Custom"') if RhoOfwater in ['Z&D 2005', 'Z&D 2009', 'Custom']: validBool = True self.RhoOfWater = RhoOfwater else: print('Please enter one of the provided options') validBool = False while not validBool: force = input('Force Custom? (yes/no)') if force == 'yes': validBool = True elif force == 'no': validBool = True self.forceCustom = False else: print('Please enter one of the provided options') validBool = False while not validBool: dia = input('Dielectric Constant Equation Option: "Supcrt", "Franck", "Fernandez", "Sverjensky", or "Custom"') if dia in ['Supcrt', 'Franck', 'Fernandez', 'Sverjensky','Custom']: validBool = True self.dielectricEq = dia else: print('Please enter one of the provided options') validBool = False while not validBool: forceS = input('Force Supcrt? (yes/no)') if forceS == 'yes': validBool = True elif forceS == 'no': validBool = True self.ForceSupcrt = False else: print('Please enter one of the provided options') validBool = False while not validBool: freeE = input('Water Free Energy Equation Option: "D&H 1978", "Integral", "Custom"') if freeE in ['D&H 1978', 'Integral', 'Custom']: validBool = True self.WaterFreeEq = freeE validBool = False while not validBool: dispO = input('Display Volume Option? (yes/no)') if dispO == 'yes': validBool = True elif dispO == 'no': validBool = True self.DisplayVolOpt = False else: print('Please enter one of the provided options') validBool = False while not validBool: PsatdispO = input('Psat Display Volume Option? (yes/no)') if PsatdispO == 'yes': validBool = True elif PsatdispO == 'no': validBool = True self.PsatDisplayVol = False else: print('Please enter one of the provided options') validBool = False while not validBool: dispV = input('Display Volume? (yes/no)') if dispV == 'yes': validBool = True elif dispV == 'no': validBool = True self.DisplayVol = False else: print('Please enter one of the provided options') if self.WaterFreeEq == "Custom" or self.dielectricEq == "Custom" or self.RhoOfWater == "Custom": self.dielectricCollection, self.densityCollection, self.gibbsCollection = self.import_custom_sheets() return
def set_tp(self, pt_arr)
-
Setting the PT values, but automated for the helperfunction. Can also be used to quick set tp with prompted input
Expand source code
def set_tp(self, pt_arr): '''Setting the PT values, but automated for the helperfunction. Can also be used to quick set tp with prompted input''' pressArr = [] tempArr = [] self.RhoWatArr = [] self.DiaArr = [] self.QArr =[] self.gibbsLst = [] self.logK = [] self.vLst = [] self.delG = [] self.delV = [] if self.ptInput == "Custom": ptSheet =pd.read_csv(inpPath,encoding= 'unicode_escape', header = None) ptFinder = ptSheet.to_numpy() tempArr = [float(i[1]) for i in ptFinder[4:]] pressArr = [float(i[0]) for i in ptFinder[4:]] elif self.ptInput == "Regular": try: templow = pt_arr[0][0] temphigh =pt_arr[0][1] tempstep = pt_arr[0][2] pmin = pt_arr[1][0] pmax = pt_arr[1][1] pstep = pt_arr[1][2] except ValueError: print('Your PT array is not formatted correctly. Please use the format [[tmin, tmax, tstep][pmin, pmax, pstep]]') tempArr = np.arange(start= templow, stop = temphigh + 1, step = tempstep) parrHelp = np.arange(start= pmin, stop = pmax + 1, step = pstep) for i in range(len(parrHelp)): pressArr.append([parrHelp[i]]* len(tempArr)) pressArr = np.multiply(pressArr, 1000) tempArr = [tempArr] * len(parrHelp) elif self.ptInput == "Psat": try: templow = pt_arr[0] temphigh = pt_arr[1] tempstep = pt_arr[2] validBool = True except ValueError: print('Your input is not formatted correctly. Please use the format for psat of [tmin, tmax, tstep]') tempArr = np.arange(start= templow, stop = temphigh + 1, step = tempstep) for i in range(len(tempArr)): if tempArr[i] < 100: pressArr.append(1) else: pressArr.append(2.1650906415E-11*np.double(tempArr[i])**5 + 0.0008467019353*np.double(tempArr[i])**2 - 0.17973651666*tempArr[i] + 10.7768850763807) else: # If I've done the checking correctly above it should never reach this raise ValueError("You have not set your options yet, please set them before continuing") self.tempUsed = np.ndarray.flatten(np.asarray(tempArr)) self.pressureUsed = np.ndarray.flatten(np.asarray(pressArr)) self.tKelvin = np.add(self.tempUsed, 273.15) # code to set options in a way the equations can understand if self.ptInput == "Psat": self.psat = True else: self.psat = False if self.RhoOfWater =='Z&D 2005': self.equation = 1 elif self.RhoOfWater == 'Z&D 2009': self.equation = 2 else: self.equation = 3 if self.dielectricEq == "Supcrt": self.diaEq = 1 elif self.dielectricEq == "Franck": self.diaEq = 2 elif self.dielectricEq == "Fernandez": self.diaEq = 3 elif self.dielectricEq == "Sverjensky": self.diaEq = 4 else: self.diaEq = 5 # write code to take in custom Rho, G, and Water Values here self.densityCollection = np.asarray(self.densityCollection).astype(float) self.dielectricCollection = np.asarray(self.dielectricCollection).astype(float) self.gibbsCollection = np.asarray(self.gibbsCollection).astype(float) # Sets the water density array for i in range(len(self.pressureUsed)): # For the custom array if self.RhoOfWater =="Custom" or (self.forceCustom == True and self.pressureUsed[i] < 1000): idx = np.intersect1d(np.where(np.asarray(self.densityCollection).astype(float) == self.pressureUsed[i]/1000), np.where(np.asarray(self.densityCollection).astype(float) == self.tempUsed[i]))[0] if not np.isnan(self.densityCollection[idx][2]): self.RhoWatArr.append(self.densityCollection[idx][2]) else: self.RhoWatArr.append(0) else: self.RhoWatArr.append(DEWEquations.DEWEquations.calculateDensity(self.pressureUsed[i], self.tempUsed[i], self.equation, 0.01, self.psat)) # Sets the dielectric constant array for i in range(len(self.pressureUsed)): # for the custom array if self.dielectricEq == "Custom": idx = np.intersect1d(np.where(np.asarray(self.dielectricCollection).astype(float) == self.pressureUsed[i]/1000), np.where(np.asarray(self.dielectricCollection).astype(float) == self.tempUsed[i]))[0] if not np.isnan(self.dielectricCollection[idx][2]): self.DiaArr.append(self.dielectricCollection[idx][2]) else: self.DiaArr.append(0) else: if self.ForceSupcrt == True and self.pressureUsed[i] < 5000 and self.psat == False: self.DiaArr.append(DEWEquations.DEWEquations.calculateEpsilon(self.RhoWatArr[i], self.tempUsed[i], 1, self.psat)) else: self.DiaArr.append(DEWEquations.DEWEquations.calculateEpsilon(self.RhoWatArr[i], self.tempUsed[i], self.diaEq, self.psat)) # Sets up the Q array for i in range(len(self.pressureUsed)): if self.DisplayVol == True: try: self.QArr.append(float(DEWEquations.DEWEquations.calculateQ(self.pressureUsed[i], self.tempUsed[i], self.RhoWatArr[i], self.equation, self.diaEq, self.psat))*np.double(10)**6) except: self.QArr.append(0) else: self.QArr.append(0) # Sets up custom Gibbs of Water Array: if self.WaterFreeEq == "Custom": for i in range(len(self.pressureUsed)): idx = np.intersect1d(np.where(np.asarray(self.gibbsCollection).astype(float) == self.pressureUsed[i]/1000), np.where(np.asarray(self.gibbsCollection).astype(float) == self.tempUsed[i]))[0] if not np.isnan(self.gibbsCollection[idx][2]): self.GibbsH2O.append(self.gibbsCollection[idx][2]) else: self.GibbsH2O.append(0) return
def supcrt_inp(self, rxn_lst, title, reaction_type='psat')
-
Takes a list of reaction lists (comprised of tuples) and runs supcrt
Expand source code
def supcrt_inp(self, rxn_lst, title, reaction_type = 'psat'): '''Takes a list of reaction lists (comprised of tuples) and runs supcrt''' for reaction in rxn_lst: sup_path = '/'.join(('resources', 'supcrt96.exe')) supPath = pkg_resources.resource_filename(resource_package, sup_path) self.proc = subprocess.Popen(supPath,stdout=subprocess.PIPE, stdin=subprocess.PIPE,stderr=subprocess.STDOUT, shell=True) self.pout = self.proc.stdout self.pin = self.proc.stdin it = 0 rxnVar = 'realReac.con' if reaction_type != 'psat': rxnVar = 'Xtend.con' if len(title) < 1: title = input('What is the title of your reaction?') comm = ['n', 'updateSlop1.dat', '2', rxnVar, '2', '1', title] for component in reaction: if component[1] not in nameLst: print(str(component[1]) + ' is not in the slop16 database. Please check your spelling and try again. You can use the search function the query the database.') else: comm.append(str(component[0]) + ' ' + component[1]) comm.append('0') comm.append('y') comm.append('n') comm.append(title + '.txt') comm.append('1') comm.append('1') comm.append('empty') threading.Thread(target=self.outLoop2).start() while(self.proc.poll() is None): try: inp = comm[it] it += 1 # inp = bytearray(input('User Input: ')+'\n',sys.stdin.encoding) if(self.proc.poll() is None): self.pin.write(bytearray(inp+'\n',sys.stdin.encoding)) self.pin.flush() except: pass return
class DEWEquations
-
The class here imports all the equations that the authors of the Deep Earth Water Model Excel Sheet use and converts them into Python
Expand source code
class DEWEquations: '''The class here imports all the equations that the authors of the Deep Earth Water Model Excel Sheet use and converts them into Python''' def calculateDensity(pressure, temperature, equation, error, Psat): ''' Function to calculate the density of water. Essentially performs guesses and checks with different densities until it reaches the correct pressure down to two decimal places, as calculated by either Zhang & Duan (2005) or Zhang & Duan (2009). ---Input--- pressure - The pressure to calculate the density of water at, in bars temperature - The temperature to calculate the density of water at, in Celsius equation - Determines which equation of state to use in calculating the density. equation = 1 corresponds to using Zhang & Duan (2005) equation = 2 corresponds to using Zhang & Duan (2009) error - This function uses a form of the bisection method. This variable indicates how close the approximation should get. Eg. if error = 0.01, the density calculated will calculate the pressure using the respective equation accurate to 0.01 of the input pressure Psat - Determines if the polynomial fit to psat densities should be used in the event that calculations are along the Psat curve ---Output--- Returns the density of water at the input pressure and temperature, in units of g/cm^3. The density returned will calculate a pressure which differs from the input pressure by the value of "error" or less. If a proper value for the equation was not entered, zero is returned. ''' fn_return_value = 0 if Psat == True: #This equation models the density of water as a function of temperature along the Psat curve. #It has an R^2 value of 0.9999976885 as compared with Supcrt92 values. fn_return_value = - 1.01023381581205E-104 * pow(temperature, np.double(40)) + - 1.1368599785953E-27 * pow(temperature, np.double(10)) + - 2.11689207168779E-11 * pow(temperature, np.double(4)) + 1.26878850169523E-08 * pow(temperature, np.double(3)) + - 4.92010672693621E-06 * pow(temperature, np.double(2)) + - 3.2666598612692E-05 * temperature + 1.00046144613017 else: #Define variables minGuess = 0.00001 guess = 0.00001 maxGuess = 7.5 * equation - 5 calcP = 0 #Loop through and find the density for i in range(1, 51): #Calculates the pressure using the specified equation calcP = DEWEquations.calculatePressure(guess, temperature, equation) #If the calculated pressure is not equal to input pressure, this determines a new #guess for the density based on current guess and how the calculated pressure #relates to the input pressure. In effect, this a form of a bisection method. if np.absolute(calcP - pressure) > error: if calcP > pressure: maxGuess = guess guess = ( guess + minGuess ) / 2 elif calcP < pressure: minGuess = guess guess = ( guess + maxGuess ) / 2 else: fn_return_value = guess break return fn_return_value def calculatePressure(density, temperature, equation): '''Calculates the pressure of water as a function of density and temperature using one of two equation of states. ---Input--- density - The density to use in finding a pressure, in g/cm^3 temperature - The temperature to use in finding a pressure, in Celsius equation - The equation of state to use when calculating the pressure. equation = 1 corresponds to using Zhang & Duan (2005) equation = 2 corresponds to using Zhang & Duan (2009) ---Output--- Returns the pressure of water corresponding to the input density and temperature, in units of bars. If a proper value for the equation was not entered, zero is returned. ''' B = None C = None D = None E = None f = None g = None m = None m = np.double(18.01528) select_variable_0 = equation if (select_variable_0 == 1): ZD05_R = 83.144 ZD05_Vc = 55.9480373 ZD05_Tc = 647.25 TK = temperature + 273.15 Vr = m / density / ZD05_Vc Tr = TK / ZD05_Tc B = 0.349824207 - 2.91046273 / ( Tr * Tr ) + 2.00914688 / ( Tr * Tr * Tr ) C = 0.112819964 + 0.748997714 / ( Tr * Tr ) - 0.87320704 / ( Tr * Tr * Tr ) D = 0.0170609505 - 0.0146355822 / ( Tr * Tr ) + 0.0579768283 / ( Tr * Tr * Tr ) E = - 0.000841246372 + 0.00495186474 / ( Tr * Tr ) - 0.00916248538 / ( Tr * Tr * Tr ) f = - 0.100358152 / Tr g = np.double(- 0.00182674744 * Tr) delta = 1 + B / Vr + C / ( Vr * Vr ) + D / pow(Vr, np.double(4)) + E / pow(Vr, np.double(5)) + ( f / ( Vr * Vr ) + g / pow(Vr, np.double(4)) ) * np.exp(- 0.0105999998 / ( Vr * Vr )) fn_return_value = ZD05_R * TK * density * delta / m elif (select_variable_0 == 2): ZD09_R = 0.083145 #Constant equal to ZD09_epsilon / (3.0626 * ZD09_omega^3) ZD09_c1 = 6.971118009 #ZD09_epsilon = 510 'Lenard-Jones parameter in units of K #ZD09_omega = 2.88 'Lenard-Jones parameter in units of 1E-10 m #Prefactor calculated from 1000 * pow(ZD09_omega / 3.691, 3) dm = 475.05656886 * density #Prefactor calculated from 0.001 * pow(3.691 / ZD09_omega, 3) Vm = 0.0021050125 * ( m / density ) #Prefactor calculated from 154 / ZD09_epsilon Tm = 0.3019607843 * ( temperature + 273.15 ) B = 0.029517729893 - 6337.56452413 / ( Tm * Tm ) - 275265.428882 / ( Tm * Tm * Tm ) C = 0.00129128089283 - 145.797416153 / ( Tm * Tm ) + 76593.8947237 / ( Tm * Tm * Tm ) D = 2.58661493537E-06 + 0.52126532146 / ( Tm * Tm ) - 139.839523753 / ( Tm * Tm * Tm ) E = - 2.36335007175E-08 + 0.00535026383543 / ( Tm * Tm ) - 0.27110649951 / ( Tm * Tm * Tm ) f = 25038.7836486 / ( Tm * Tm * Tm ) delta = 1 + B / Vm + C / ( Vm * Vm ) + D / pow(Vm, 4) + E / pow(Vm, 5) + f / ( Vm * Vm ) * ( 0.73226726041 + 0.015483335997 / ( Vm * Vm ) ) * np.exp(- 0.015483335997 / ( Vm * Vm )) Pm = ZD09_R * Tm * delta / Vm fn_return_value = Pm * ZD09_c1 else: fn_return_value = 0 return fn_return_value def calculate_drhodP(density, temperature, equation): '''Calculates the partial derivative of density with respect to pressure, i.e. (d(rho)/dP)_T This is done using one of two equations of state for water. ---Input--- density - The density of water, in g/cm^3 temperature - The temperature of water, in Celsius equation - The equation of state to use when calculating the pressure. equation = 1 corresponds to using Zhang & Duan (2005) equation = 2 corresponds to using Zhang & Duan (2009) ---Output--- Returns the partial derivative of density with respect to pressure of water corresponding to the input density and temperature, in units of g^3/cm^3/bar. If a proper value for the equation was not entered, zero is returned. ''' B = None C = None D = None E = None f = None g = None m = None m = np.double(18.01528) select_variable_1 = equation if (select_variable_1 == 1): ZD05_R = 83.144 ZD05_Vc = 55.9480373 ZD05_Tc = 647.25 TK = np.double(temperature + 273.15) Tr = TK / ZD05_Tc cc = ZD05_Vc / m Vr = m / ( density * ZD05_Vc ) B = 0.349824207 - 2.91046273 / ( Tr * Tr ) + 2.00914688 / ( Tr * Tr * Tr ) C = 0.112819964 + 0.748997714 / ( Tr * Tr ) - 0.87320704 / ( Tr * Tr * Tr ) D = 0.0170609505 - 0.0146355822 / ( Tr * Tr ) + 0.0579768283 / ( Tr * Tr * Tr ) E = - 0.000841246372 + 0.00495186474 / ( Tr * Tr ) - 0.00916248538 / ( Tr * Tr * Tr ) f = - 0.100358152 / Tr ##### # This value has been edited to be consistent with Mark Ghiorso's objective-C version of DEW and the original Zhang and Duan 2005 paper, # although it is incosistent with the Excel-implemented DEW Model g = np.double(- 0.00182674744 * Tr) ######## delta = 1 + B / Vr + C / ( Vr * Vr ) + D / pow(Vr, 4) + E / pow(Vr, 5) + ( f / ( Vr * Vr ) + g / pow(Vr, 4) ) * np.exp(- 0.0105999998 / pow(Vr, 2)) kappa = B * cc + 2 * C * ( cc * cc ) * density + 4 * D * pow(cc, 4) * pow(density, 3) + 5 * E * pow(cc, 5) * pow(density, 4) + ( 2 * f * ( cc * cc ) * density + 4 * g * pow(cc, 4) * pow(density, 3) - ( f / ( Vr * Vr ) + g / pow(Vr, 4) ) * ( 2 * 0.0105999998 * ( cc * cc ) * density ) ) * np.exp(- 0.0105999998 / ( Vr * Vr )) fn_return_value = m / ( ZD05_R * TK * ( delta + density * kappa ) ) elif (select_variable_1 == 2): ZD09_R = 0.083145 ZD09_c1 = 6.971118009 #ZD09_epsilon = 510 'Lenard-Jones parameter in units of K #ZD09_omega = 2.88 'Lenard-Jones parameter in units of 1E-10 m #Prefactor calculated from 1000 * pow(ZD09_omega / 3.691, 3) dm = 475.05656886 * density #Prefactor calculated from 0.001 * pow(3.691 / ZD09_omega, 3) Vm = 0.0021050125 * ( m / density ) #Prefactor calculated from 154 / ZD09_epsilon Tm = 0.3019607843 * ( temperature + 273.15 ) B = 0.029517729893 - 6337.56452413 / ( Tm * Tm ) - 275265.428882 / ( Tm * Tm * Tm ) C = 0.00129128089283 - 145.797416153 / ( Tm * Tm ) + 76593.8947237 / ( Tm * Tm * Tm ) D = 2.58661493537E-06 + 0.52126532146 / ( Tm * Tm ) - 139.839523753 / ( Tm * Tm * Tm ) E = - 2.36335007175E-08 + 0.00535026383543 / ( Tm * Tm ) - 0.27110649951 / ( Tm * Tm * Tm ) f = 25038.7836486 / ( Tm * Tm * Tm ) delta = 1 + B / Vm + C / ( Vm * Vm ) + D / pow(Vm, 4) + E / pow(Vm, 5) + f / ( Vm * Vm ) * ( 0.73226726041 + 0.015483335997 / ( Vm * Vm ) ) * np.exp(- 0.015483335997 / ( Vm * Vm )) kappa = B / m + 2 * C * dm / ( m * m ) + 4 * D * pow(dm, 3) / pow(m, 4) + 5 * E * pow(dm, 4) / pow(m, 5) + ( 2 * f * dm / ( m * m ) * ( 0.73226726041 + 0.015483335997 / ( Vm * Vm ) ) + f / pow(Vm, 2) * ( 1 - 0.73226726041 - 0.015483335997 / ( Vm * Vm ) ) * ( 2 * 0.015483335997 * dm / ( m * m ) ) ) * np.exp(- 0.015483335997 / ( Vm * Vm )) ##### Adding a comment here because I've made ZD09_c4 into ZD09 C_1 ####### ##### Original line###### #fn_return_value = ZD09_c1 * m / ( ZD09_c4 * ZD09_R * Tm * ( delta + dm * kappa ) ) fn_return_value = ZD09_c1 * m / ( ZD09_c1 * ZD09_R * Tm * ( delta + dm * kappa ) ) else: fn_return_value = 0 return fn_return_value def calculateGibbsOfWater(pressure, temp, equation, densityEquation, Psat): '''This function calculates the Gibbs Free Energy of Water. It can calculate with two equations. ---Input---' pressure - The pressure to calculate the Gibbs Free Energy at, in bars temperature - The temperature to calculate the Gibbs Free Energy at, in Celsius equation - Determines which equation to use to calculate the Gibbs Free Energy, either Delaney & Helgeson (1978), corresonding to equation = 1, or simply integrating over the volume of water, corresponding to equation = 2 density Equation - Determines which equation to use to find the density, and thus the volume of water. Psat - Determines if the calculation should be done at Psat. ---Output--- Returns the Gibbs Free Energy of water in units of cal/mol. If a proper value for equation was not entered, zero is returned. ''' if Psat == True: #This equation models the Gibbs Free Energy of water as a function of temperature along the Psat curve. #It has an R^2 value of 0.9999999984518 as compared with Supcrt92 values. fn_return_value = - 2.72980941772081E-103 * pow(temp, np.double(40)) + 2.88918186300446E-25 * pow(temp, np.double(10)) + - 2.21891314234246E-08 * pow(temp, np.double(4)) + 3.0912103873633E-05 * pow(temp, np.double(3)) + - 3.20873264480928E-02 * pow(temp, np.double(2)) + - 15.169458452209 * temp + - 56289.0379433809 else: select_variable_2 = equation if (select_variable_2 == 1): coeff = {} coeff[0] = - 56130.073 coeff[1] = 0.38101798 coeff[2] = - 0.0000021167697 coeff[3] = 2.0266445E-11 coeff[4] = - 8.3225572E-17 coeff[5] = - 15.285559 coeff[6] = 0.0001375239 coeff[7] = - 1.5586868E-09 coeff[8] = 6.6329577E-15 coeff[9] = - 0.026092451 coeff[10] = 0.000000035988857 coeff[11] = - 2.7916588E-14 coeff[12] = 0.000017140501 coeff[13] = - 1.6860893E-11 coeff[14] = - 6.0126987E-09 gibbsFreeEnergy = 0 Count = 0 for j in range(0, 5): for k in range(0, 5 - j): temp = np.absolute(temp) gibbsFreeEnergy = gibbsFreeEnergy + coeff[Count] * pow((temp), np.double(j)) * pow(pressure, np.double(k)) Count = Count + 1 fn_return_value = gibbsFreeEnergy elif (select_variable_2 == 2): #then defines the gibbs free energy as the integral over the volume as a function of temperature. #We can only perform this calculation if we can use one of the two density equations included #in the code. If densityEquation equals three, then that implies the user chose to use custom #density values. Because this procedure requires integration over a range of densities, this #cannot be calculated if the user has custom density values. Therefore, this will just return zero. if ( densityEquation == 3 ) : fn_return_value = 0 #Gibbs Free Energy of water at 1 kb. This equation is a polynomial fit to data as a function of temperature. #It is valid in the range of 100 to 1000 C. temp = np.absolute(temp) GAtOneKb = 2.6880734E-09 *(temp * temp)*(temp*temp) + 0.00000063163061 * (temp * temp * temp) - 0.019372355 * ( temp * temp ) - 16.945093 * temp - 55769.287 if pressure < 1000: fn_return_value = 0 elif pressure == 1000: fn_return_value = GAtOneKb elif pressure > 1000: integral = 0 #Integral is sum of rectangles with this width. This function in effect limits the spacing #to 20 bars so that very small pressures do not have unreasonably small widths. Otherwise the width #is chosen such that there are always 500 steps in the numerical integration. This ensures that for very #high pressures, there are not a huge number of steps calculated which is very computationally taxing. if ( pressure - 1000 ) / 500 < 20: spacing = 20 else: spacing = ( pressure - 1000 ) / 500 for i in range(1000, pressure + 1, int(spacing)): #This integral determines the density only down to an error of 100 bars #rather than the standard of 0.01. This is done to save computational #time. Tests indicate this reduces the computation by about a half while #introducing little error from the standard of 0.01. integral = integral + ( 18.01528 / DEWEquations.calculateDensity(i, temp, densityEquation, 100, False) / 41.84 ) * spacing fn_return_value = GAtOneKb + integral else: fn_return_value = 0 return fn_return_value def calculateEpsilon(density, temperature, equation, Psat): ''' This function calculates the dielectric constant (epsilon) of water using one of four possible equations. ---Input--- density - The density of water to use in calculating epsilon, in g/cm^3 temperature - The temperature to calculate epsilon with, in Celsius equation - Determines which equation should be used to calculate the dielectric constant of water. equation = 1 corresponds to using Johnson & Norton (1991), the equation used in Supcrt equation = 2 corresponds to using Franck (1990) equation = 3 corresponds to using Fernandez (1997) equation = 4 corredponds to using the Power Function. This is an equation derived by Dimitri Sverjensky and Brandon Harison at Johns Hopkins University. Psat - Determines if the polynomial fit to psat dielectric constant values should be used in the event that calculations are along the Psat curve ---Output--- Returns the Dielectric constant of water at the given density and temperature. If a proper value for equation was not entered, zero is returned. ''' if Psat == True: #This equation models the dielectric constant of water as a function of temperature along the Psat curve. #It has an R^2 value of 0.9999991719 as compared with Supcrt92 values. fn_return_value = - 1.66686763214295E-77 * pow(temperature, np.double(30)) + - 9.02887020379887E-07 * pow(temperature, np.double(3)) + 8.4590281449009E-04 * pow(temperature, np.double(2)) + - 0.396542037778945 * temperature + 87.605024245432 else: select_variable_3 = equation if (select_variable_3 == 1): T_hat = ( temperature + 273.15 ) / 298.15 k0 = 1 k1 = 14.70333593 / T_hat k2 = 212.8462733 / T_hat - 115.4445173 + 19.55210915 * T_hat k3 = - 83.3034798 / T_hat + 32.13240048 * T_hat - 6.69409865 * ( T_hat * T_hat ) k4 = - 37.86202045 / ( T_hat * T_hat ) + 68.87359646 / T_hat - 27.29401652 fn_return_value = k0 + k1 * density + k2 * ( density * density ) + k3 * pow(density, 3) + k4 * pow(density, 4) elif (select_variable_3 == 2): pi = 3.14159265358979 omega = 0.0000000268 k = 1.380648E-16 Na = 6.022E+23 mu = 2.33E-18 rhostar = ( density * 0.055508 ) * pow(omega, 3) * Na mustarsq = pow(mu, 2) / ( k * ( temperature + 273.15 ) * pow(omega, 3) ) y = ( 4 * pi / 9 ) * rhostar * mustarsq f1 = 0.4341 * pow(rhostar, 2) f2 = - ( 0.05 + 0.75 * pow(rhostar, 3) ) f3 = - 0.026 * pow(rhostar, 2) + 0.173 * pow(rhostar, 4) fn_return_value = ( ( 3 * y ) / ( 1 - f1 * y ) ) * ( 1 + ( 1 - f1 ) * y + f2 * ( y * y ) + f3 * ( y * y * y ) ) + 1 elif (select_variable_3 == 3): #Values for N_k N_k = {} N_k[0] = 0.978224486826 N_k[1] = - 0.957771379375 N_k[2] = 0.237511794148 N_k[3] = 0.714692224396 N_k[4] = - 0.298217036956 N_k[5] = - 0.108863472196 N_k[6] = 0.0949327488264 N_k[7] = - 0.00980469816509 N_k[8] = 0.000016516763497 N_k[9] = 9.37359795772E-05 N_k[10] = - 1.2317921872E-10 N_k[11] = 0.00196096504426 #Values for i_k i_k = {} i_k[0] = 1 i_k[1] = 1 i_k[2] = 1 i_k[3] = 2 i_k[4] = 3 i_k[5] = 3 i_k[6] = 4 i_k[7] = 5 i_k[8] = 6 i_k[9] = 7 i_k[10] = 10 #Values for j_k j_k = {} j_k[0] = 0.25 j_k[1] = 1 j_k[2] = 2.5 j_k[3] = 1.5 j_k[4] = 1.5 j_k[5] = 2.5 j_k[6] = 2 j_k[7] = 2 j_k[8] = 5 j_k[9] = 0.5 j_k[10] = 10 avogadro = 6.0221367E+23 dipole = 6.138E-30 epsilon_o = 8.8541878176204E-12 boltzmann = 1.380658E-23 alpha = 1.636E-40 density_c = 17873.728 T_c = 647.096 #Convert density and temperature units density_molm3 = density * 0.055508 * 1000000 T_K = temperature + 273.15 #Defining the g equation g = 1 for ii in range(0, 11): g = g + N_k[ii] * pow(density_molm3 / density_c, np.double(i_k[ii])) * pow(T_c / T_K, np.double(j_k[ii])) g = g + N_k[11] * ( density_molm3 / density_c ) * pow(T_K / 228 - 1, - 1.2) #Defining the A, B, and C equations A = ( avogadro * pow(dipole, 2) * density_molm3 * g ) / ( epsilon_o * boltzmann * T_K ) B = ( avogadro * alpha * density_molm3 ) / ( 3 * epsilon_o ) C = 9 + 2 * A + 18 * B + A * A + 10 * A * B + 9 * B * B fn_return_value = ( 1 + A + 5 * B + np.sqrt(C) ) / ( 4 - 4 * B ) elif (select_variable_3 == 4): #Relevant parameters a1 = - 1.57637700752506E-03 a2 = 6.81028783422197E-02 a3 = 0.754875480393944 b1 = - 8.01665106535394E-05 b2 = - 6.87161761831994E-02 b3 = 4.74797272182151 A = a1 * temperature + a2 * np.sqrt(temperature) + a3 B = b1 * temperature + b2 * np.sqrt(temperature) + b3 fn_return_value = np.exp(B) * pow(density, np.double(A)) else: fn_return_value = 0 return fn_return_value def calculate_depsdrho(density, temperature, equation): '''Calculates the partial derivative of the dielectric constant (epsilon) with respect to density, i.e. (d(eps)/d(rho))_T This is done using one of four possible equations ---Input--- density - The density of water to calculate with, in g/cm^3 temperature - The temperature to calculate with, in Celsius equation - Determines which equation should be used to calculate the derivative equation = 1 corresponds to using Johnson & Norton (1991), the equation used in Supcrt equation = 2 corresponds to using Franck (1990) equation = 3 corresponds to using Fernandez (1997) equation = 4 corredponds to using the Power Function. This is an equation derived by Dimitri Sverjensky and Brandon Harison at Johns Hopkins University. ---Output--- Returns the partial derivative of the dielectric constant with respect to density in units of cm^3/g. If a proper value for equation was not entered, zero is returned. ''' select_variable_4 = equation if (select_variable_4 == 1): T_hat = ( temperature + 273.15 ) / 298.15 k1 = 14.70333593 / T_hat k2 = 212.8462733 / T_hat - 115.4445173 + 19.55210915 * T_hat k3 = - 83.3034798 / T_hat + 32.13240048 * T_hat - 6.69409865 * ( T_hat * T_hat ) k4 = - 37.86202045 / ( T_hat * T_hat ) + 68.87359646 / T_hat - 27.29401652 fn_return_value = k1 + 2 * k2 * density + 3 * k3 * pow(density, 2) + 4 * k4 * pow(density, 3) elif (select_variable_4 == 2): pi = 3.14159265358979 omega = 0.0000000268 k = 1.380648E-16 Na = 6.022E+23 mu = 2.33E-18 density = density * 0.055508 cc = pow(omega, 3) * Na rhostar = density * cc mustarsq = pow(mu, 2) / ( k * ( temperature + 273.15 ) * pow(omega, 3) ) y = ( 4 * pi / 9 ) * rhostar * mustarsq f1 = 0.4341 * pow(rhostar, 2) f2 = - ( 0.05 + 0.75 * pow(rhostar, 3) ) f3 = - 0.026 * pow(rhostar, 2) + 0.173 * pow(rhostar, 4) dydrho = ( 4 * pi / 9 ) * mustarsq * cc df1drho = 2 * 0.4341 * pow(cc, 2) * density df2drho = - 3 * 0.75 * pow(cc, 3) * pow(density, 2) df3drho = - 2 * 0.026 * pow(cc, 2) * density + 4 * 0.173 * pow(cc, 4) * pow(density, 3) eps = ( ( 3 * y ) / ( 1 - f1 * y ) ) * ( 1 + ( 1 - f1 ) * y + f2 * ( y * y ) + f3 * ( y * y * y ) ) + 1 #The 0.055508 value converts the units from cm^3/mol to cm^3/g fn_return_value = 0.05508 * ( ( ( dydrho + pow(y, 2) * df1drho ) / ( 1 - f1 * y ) ) * ( eps - 1 ) / y + ( ( 3 * y ) / ( 1 - f1 * y ) ) * ( - df1drho * y + df2drho * pow(y, 2) + df3drho * pow(y, 3) + ( 1 - f1 + 2 * f2 * y + 3 * f3 * y * y ) * dydrho ) ) elif (select_variable_4 == 3): #Values for N_k N_k = {} N_k[0] = 0.978224486826 N_k[1] = - 0.957771379375 N_k[2] = 0.237511794148 N_k[3] = 0.714692224396 N_k[4] = - 0.298217036956 N_k[5] = - 0.108863472196 N_k[6] = 0.0949327488264 N_k[7] = - 0.00980469816509 N_k[8] = 0.000016516763497 N_k[9] = 9.37359795772E-05 N_k[10] = - 1.2317921872E-10 N_k[11] = 0.00196096504426 #Values for i_k i_k = {} i_k[0] = 1 i_k[1] = 1 i_k[2] = 1 i_k[3] = 2 i_k[4] = 3 i_k[5] = 3 i_k[6] = 4 i_k[7] = 5 i_k[8] = 6 i_k[9] = 7 i_k[10] = 10 #Values for j_k j_k = {} j_k[0] = 0.25 j_k[1] = 1 j_k[2] = 2.5 j_k[3] = 1.5 j_k[4] = 1.5 j_k[5] = 2.5 j_k[6] = 2 j_k[7] = 2 j_k[8] = 5 j_k[9] = 0.5 j_k[10] = 10 avogadro = 6.0221367E+23 dipole = 6.138E-30 epsilon_o = 8.8541878176204E-12 boltzmann = 1.380658E-23 alpha = 1.636E-40 density_c = 17873.728 T_c = 647.096 #Convert density and temperature units density_molm3 = density * 0.055508 * 1000000 T_K = temperature + 273.15 #Defining the g equation g = 1 for ii in range(0, 11): g = g + N_k[ii] * pow(density_molm3 / density_c, np.double(i_k[ii])) * pow(T_c / T_K, np.double(j_k[ii])) g = g + N_k[11] * ( density_molm3 / density_c ) * pow(T_K / 228 - 1, - 1.2) #Defining the dgdrho equation dgdrho = 0 for ii in range(0, 11): dgdrho = dgdrho + i_k[ii] * N_k[ii] * ( pow(density_molm3, np.double(i_k[ii] - 1)) / pow(density_c, np.double(i_k[ii])) ) * pow(T_c / T_K, np.double(j_k[ii])) dgdrho = dgdrho + ( N_k[11] / density_c ) * pow(T_K / 228 - 1, - 1.2) #Defining the A, B, and C equations A = ( avogadro * pow(dipole, 2) * density_molm3 * g ) / ( epsilon_o * boltzmann * T_K ) B = ( avogadro * alpha * density_molm3 ) / ( 3 * epsilon_o ) C = 9 + 2 * A + 18 * B + A * A + 10 * A * B + 9 * B * B #Defining the derivatives and epsilon dAdrho = A / density_molm3 + ( A / g ) * dgdrho dBdrho = B / density_molm3 dCdrho = 2 * dAdrho + 18 * dBdrho + 2 * A * dAdrho + 10 * ( dAdrho * B + A * dBdrho ) + 18 * B * dBdrho eps = ( 1 + A + 5 * B + pow(np.double(C), 0.5)) / ( 4 - 4 * B ) #The 55508 value converts the units from m^3/mol to cm^3/g fn_return_value = 55508 * ( 1 / ( 4 - 4 * B ) ) * ( 4 * dBdrho * eps + dAdrho + 5 * dBdrho + 0.5 * pow(np.double(C), - 0.5) * dCdrho ) elif (select_variable_4 == 4): #Relevant parameters a1 = - 1.57637700752506E-03 a2 = 6.81028783422197E-02 a3 = 0.754875480393944 b1 = - 8.01665106535394E-05 b2 = - 6.87161761831994E-02 b3 = 4.74797272182151 A = a1 * temperature + a2 * np.sqrt(temperature) + a3 B = b1 * temperature + b2 * np.sqrt(temperature) + b3 fn_return_value = A * np.exp(B) * pow(density, A - 1) else: fn_return_value = 0 return fn_return_value def calculateOmega(P, T, density, name, wref, Z): '''This function calculates the born coefficient omega for aqueous species as a function of pressure and temeprature ---Input--- P - Pressure to calculate at, in bars T - Temperature to calculate at, in Celsius density - Density of water to calculate omega at, in g/cm^3. This could be calculated from P and T, but it is used as an input parameter to save on calculation time. name - The name of the species this is being calculated for. wref - The value of omega at standard pressure and temperature, in units of cal/mol. This should not be the value generally given as omega*1E-5, but rather the actual value of omega. Z - The charge of the species ---Output--- Returns the value of omega at the input P and T. If Z is zero, the wprtr value is used. The value returned is in units of cal/mol and NOT multiplied by 10^-5. ''' #If species is hydrogen, the species is neutral, or the pressure is above 6 kb, #this equation is not necessary because omega is very close to wref. if name == 'H+' or Z == 0 or P > 6000: fn_return_value = wref else: #These equations are given by Shock et al. (1992) eta = 166027 #Defines the electrostatic radius at reference pressure and temperature reref = Z * Z / ( wref / eta + Z / 3.082 ) #This represents the pressure and temperature dependent solvent function g = DEWEquations.calculateG(P, T, density) #Defines the electrostatic radius at the input P and T re = reref + np.abs(Z) * g fn_return_value = eta * ( Z * Z / re - Z / ( 3.082 + g ) ) return fn_return_value def calculateG(P, T, density): '''Calculates the pressure and temperature dependent solvent function. This function should only be used for pressures less than 6 kb. ---Input--- P - The pressure to calculate at, in bars T - The temperature to calculate at, in celsius density - The density of water at which to calculate g at, in g/cm^3 ---Output--- Returns the value of the g function. If the density is greather than 1 g/cm^3, then zero is returned.''' if density >= 1: fn_return_value = 0 else: a_g = - 2.037662 + 0.005747 * T - 0.000006557892 * T * T b_g = 6.107361 - 0.01074377 * T + 0.00001268348 * T * T #Calculates the difference function in the case where we need to calculate at Psat conditions if ( P <= 1000 and T >= 155 and T <= 355 ) : f = ( pow(( T - 155 ) / 300, 4.8) + 36.66666 * pow(( T - 155 ) / 300, np.double(16)) ) *( - 1.504956E-10 * pow(1000 - P, np.double(3)) + 5.017997E-14 * pow(1000 - P, np.double(4)) ) else: f = 0 fn_return_value = a_g * pow(1 - density, b_g) - f return fn_return_value def calculate_domegadP(P, T, density, name, wref, Z, densityEquation, Psat): '''This function calculates the derivative of the born coefficient omega with respect to pressure for aqueous species as a function of pressure and temeprature ---Input--- P - Pressure to calculate at, in bars T - Temperature to calculate at, in Celsius density - Density of water to calculate omega at, in g/cm^3. This could be calculated from P and T, but it is used as an input parameter to save on calculation time. name - The name of the species this is being calculated for. wref - The value of omega at standard pressure and temperature, in units of cal/mol. This should not be the value generally given as omega*1E-5, but rather the actual value of omega. Z - The charge of the species densityEquation - Determines which equation to use in calculating the derivative of density with respect to pressure. This is passed direction to calculate_dgdP equation = 1 corresponds to Zhang & Duan (2005) equation = 1 corresponds to Zhang & Duan (2009) Psat - Determines if the calculation should be done along the Psat curve. In this case there is no equation for drhodP and a polynomial fit to data from Shock et al. (1992) is used. ---Output--- Returns the value of the derivative of omega with respect to pressure at the input P and T. If Z is zero, then the derivative is zero. The value returned is in units of cal/mol/bar ''' #If species is hydrogen, the species is neutral, or the pressure is above 6 kb, #this equation is not necessary because omega is very close to wref. if name == 'H+' or Z == 0 or P > 6000: fn_return_value = 0 else: #These equations are given by Shock et al. (1992) eta = 166027 #Defines the electrostatic radius at reference pressure and temperature reref = Z * Z / ( wref / eta + Z / 3.082 ) #This represents the pressure and temperature dependent solvent function and its derivative g = DEWEquations.calculateG(P, T, density) dgdP = DEWEquations.calculate_dgdP(P, T, density, g, densityEquation, Psat) #Defines the electrostatic radius at the input P and T re = reref + np.absolute(Z) * g fn_return_value = - eta * ( np.absolute(Z * Z * Z) / pow(re, 2) - Z / pow(3.082 + g, 2) ) * dgdP return fn_return_value def calculate_dgdP(P, T, density, g, equation, Psat = True): '''Calculates the pressure derivative of the pressure and temperature dependent solvent function. This function should only be used for pressures less than 6 kb. ---Input--- P - The pressure to calculate at, in bars T - The temperature to calculate at, in celsius density - The density of water at which to calculate g at, in g/cm^3 g - The value of the g solvent function at the input P and T equation - Determines which equation to use in calculating the derivative of density with respect to pressure equation = 1 corresponds to Zhang & Duan (2005) equation = 1 corresponds to Zhang & Duan (2009) Psat - Determines if the calculation should be done along the Psat curve. In this case there is no equation for drhodP and a polynomial fit to data from Shock et al. (1992) is used. ---Output--- Returns the pressure derivative of the g function. If the density is greather than 1 g/cm^3, then zero is returned. ''' if Psat == True: #This equation models the derivative of the g solvent function with respect to pressure and #as a function of temperature along the Psat curve. #It has an R^2 value of 0.99995027718 as compared with values listed in Shock et al. (1992). #Particular care was taken to properly model the values at low temperatures which is why this #function not simply a polynomial if T < 0.01: fn_return_value = 0 else: fn_return_value = np.exp(1.37105493109451E-10 * pow(np.log(T), np.double(15)) + - 1.43605469318795E-06 * pow(np.log(T), np.double(10)) + 26.2649453651117 * np.log(T) + - 125.108856715714) * 0.000001 else: if density >= 1: fn_return_value = 0 else: b_g = 6.107361 - 0.01074377 * T + 0.00001268348 * T * T #Calculates the difference function in the case where we need to calculate at Psat conditions if ( P <= 1000 and T >= 155 and T <= 355 ) : dfdP = - ( pow(( T - 155 ) / 300, 4.8) + 36.66666 * pow(( T - 155 ) / 300, 16) ) * ( 3 * - 1.504956E-10 * pow(1000 - P, 2) + 4 * 5.017997E-14 * pow(1000 - P, 3) ) else: dfdP = 0 fn_return_value = - b_g * DEWEquations.calculate_drhodP(density, T, equation) * g / ( 1 - density ) - dfdP return fn_return_value def calculateQ(pressure, temperature, density, densityEquation, epsilonEquation, Psat): '''This method calculates the Born Coefficient Q as (1/eps^2)*(d(eps)/dP) - In other words the derivative of epsilon with respect to pressure, divided by epsilon squared ---Input--- pressure - The pressure to calculate Q at, in bars temperature - The temperature to calculate Q at, in Celsius density - The density at the input pressure and temperature, input simply to save time, in g/cm^3 denistyEquation - The density equation to use in calculating the density of water. epsilonEquation - The epsilon equation to use in calculating epsilon. Psat - Determines if the calculation should be done at Psat. ---Output--- Outputs the value of Q in units of bar^-1 Calculates the pressure and temperature dependent solvent function. This function should only be used for pressures less than 6 kb. ---Input--- P - The pressure to calculate at, in bars T - The temperature to calculate at, in celsius density - The density of water at which to calculate g at, in g/cm^3 ---Output--- Returns the value of the g function. If the density is greather than 1 g/cm^3, then zero is returned. ''' if Psat == True: #This equation models the Q Born Coefficent as a function of temperature along the Psat curve. #It has an R^2 value of 0.99999998602 as compared with values listed in Shock et al. (1992). fn_return_value = ( 1.99258688758345E-49 * pow(temperature, np.double(20)) + - 4.43690270750774E-14 * pow(temperature, np.double(6)) + 4.29110215680165E-11 * pow(temperature, np.double(5)) + - 1.07146606081182E-08 * pow(temperature, np.double(4)) + 1.09982931856694E-06 * pow(temperature, np.double(3)) + 9.60705240954956E-06 * pow(temperature, np.double(2)) + 0.642579832259358 ) * 0.000001 else: #This commented section is the code to calculate the value of Q using a finite difference derivative. #------------------------- # Dim epsilon, delta, epsilonPlusDelta As Double # # delta = 1 # # epsilon = DEWEquations.calculateEpsilon(density, temperature, epsilonEquation, False) # # epsilonPlusDelta = DEWEquations.calculateEpsilon(calculateDensity(pressure + delta, temperature, densityEquation, 0.01, False), temperature, epsilonEquation, False) # # calculateQ = (1 / pow(np.double(epsilon), 2)) * ((epsilonPlusDelta - epsilon) / delta) #------------------------- eps = DEWEquations.calculateEpsilon(density, temperature, epsilonEquation, Psat) depsdrho = DEWEquations.calculate_depsdrho(density, temperature, epsilonEquation) drhodP = DEWEquations.calculate_drhodP(density, temperature, densityEquation) fn_return_value = depsdrho * drhodP / ( eps * eps ) return fn_return_value
Methods
def calculateDensity(pressure, temperature, equation, error, Psat)
-
Function to calculate the density of water. Essentially performs guesses and checks with different densities until it reaches the correct pressure down to two decimal places, as calculated by either Zhang & Duan (2005) or Zhang & Duan (2009). —Input— pressure - The pressure to calculate the density of water at, in bars temperature - The temperature to calculate the density of water at, in Celsius equation - Determines which equation of state to use in calculating the density. equation = 1 corresponds to using Zhang & Duan (2005) equation = 2 corresponds to using Zhang & Duan (2009) error - This function uses a form of the bisection method. This variable indicates how close the approximation should get. Eg. if error = 0.01, the density calculated will calculate the pressure using the respective equation accurate to 0.01 of the input pressure Psat - Determines if the polynomial fit to psat densities should be used in the event that calculations are along the Psat curve —Output— Returns the density of water at the input pressure and temperature, in units of g/cm^3. The density returned will calculate a pressure which differs from the input pressure by the value of "error" or less. If a proper value for the equation was not entered, zero is returned.
Expand source code
def calculateDensity(pressure, temperature, equation, error, Psat): ''' Function to calculate the density of water. Essentially performs guesses and checks with different densities until it reaches the correct pressure down to two decimal places, as calculated by either Zhang & Duan (2005) or Zhang & Duan (2009). ---Input--- pressure - The pressure to calculate the density of water at, in bars temperature - The temperature to calculate the density of water at, in Celsius equation - Determines which equation of state to use in calculating the density. equation = 1 corresponds to using Zhang & Duan (2005) equation = 2 corresponds to using Zhang & Duan (2009) error - This function uses a form of the bisection method. This variable indicates how close the approximation should get. Eg. if error = 0.01, the density calculated will calculate the pressure using the respective equation accurate to 0.01 of the input pressure Psat - Determines if the polynomial fit to psat densities should be used in the event that calculations are along the Psat curve ---Output--- Returns the density of water at the input pressure and temperature, in units of g/cm^3. The density returned will calculate a pressure which differs from the input pressure by the value of "error" or less. If a proper value for the equation was not entered, zero is returned. ''' fn_return_value = 0 if Psat == True: #This equation models the density of water as a function of temperature along the Psat curve. #It has an R^2 value of 0.9999976885 as compared with Supcrt92 values. fn_return_value = - 1.01023381581205E-104 * pow(temperature, np.double(40)) + - 1.1368599785953E-27 * pow(temperature, np.double(10)) + - 2.11689207168779E-11 * pow(temperature, np.double(4)) + 1.26878850169523E-08 * pow(temperature, np.double(3)) + - 4.92010672693621E-06 * pow(temperature, np.double(2)) + - 3.2666598612692E-05 * temperature + 1.00046144613017 else: #Define variables minGuess = 0.00001 guess = 0.00001 maxGuess = 7.5 * equation - 5 calcP = 0 #Loop through and find the density for i in range(1, 51): #Calculates the pressure using the specified equation calcP = DEWEquations.calculatePressure(guess, temperature, equation) #If the calculated pressure is not equal to input pressure, this determines a new #guess for the density based on current guess and how the calculated pressure #relates to the input pressure. In effect, this a form of a bisection method. if np.absolute(calcP - pressure) > error: if calcP > pressure: maxGuess = guess guess = ( guess + minGuess ) / 2 elif calcP < pressure: minGuess = guess guess = ( guess + maxGuess ) / 2 else: fn_return_value = guess break return fn_return_value
def calculateEpsilon(density, temperature, equation, Psat)
-
This function calculates the dielectric constant (epsilon) of water using one of four possible equations. —Input— density - The density of water to use in calculating epsilon, in g/cm^3 temperature - The temperature to calculate epsilon with, in Celsius equation - Determines which equation should be used to calculate the dielectric constant of water. equation = 1 corresponds to using Johnson & Norton (1991), the equation used in Supcrt equation = 2 corresponds to using Franck (1990) equation = 3 corresponds to using Fernandez (1997) equation = 4 corredponds to using the Power Function. This is an equation derived by Dimitri Sverjensky and Brandon Harison at Johns Hopkins University. Psat - Determines if the polynomial fit to psat dielectric constant values should be used in the event that calculations are along the Psat curve —Output— Returns the Dielectric constant of water at the given density and temperature. If a proper value for equation was not entered, zero is returned.
Expand source code
def calculateEpsilon(density, temperature, equation, Psat): ''' This function calculates the dielectric constant (epsilon) of water using one of four possible equations. ---Input--- density - The density of water to use in calculating epsilon, in g/cm^3 temperature - The temperature to calculate epsilon with, in Celsius equation - Determines which equation should be used to calculate the dielectric constant of water. equation = 1 corresponds to using Johnson & Norton (1991), the equation used in Supcrt equation = 2 corresponds to using Franck (1990) equation = 3 corresponds to using Fernandez (1997) equation = 4 corredponds to using the Power Function. This is an equation derived by Dimitri Sverjensky and Brandon Harison at Johns Hopkins University. Psat - Determines if the polynomial fit to psat dielectric constant values should be used in the event that calculations are along the Psat curve ---Output--- Returns the Dielectric constant of water at the given density and temperature. If a proper value for equation was not entered, zero is returned. ''' if Psat == True: #This equation models the dielectric constant of water as a function of temperature along the Psat curve. #It has an R^2 value of 0.9999991719 as compared with Supcrt92 values. fn_return_value = - 1.66686763214295E-77 * pow(temperature, np.double(30)) + - 9.02887020379887E-07 * pow(temperature, np.double(3)) + 8.4590281449009E-04 * pow(temperature, np.double(2)) + - 0.396542037778945 * temperature + 87.605024245432 else: select_variable_3 = equation if (select_variable_3 == 1): T_hat = ( temperature + 273.15 ) / 298.15 k0 = 1 k1 = 14.70333593 / T_hat k2 = 212.8462733 / T_hat - 115.4445173 + 19.55210915 * T_hat k3 = - 83.3034798 / T_hat + 32.13240048 * T_hat - 6.69409865 * ( T_hat * T_hat ) k4 = - 37.86202045 / ( T_hat * T_hat ) + 68.87359646 / T_hat - 27.29401652 fn_return_value = k0 + k1 * density + k2 * ( density * density ) + k3 * pow(density, 3) + k4 * pow(density, 4) elif (select_variable_3 == 2): pi = 3.14159265358979 omega = 0.0000000268 k = 1.380648E-16 Na = 6.022E+23 mu = 2.33E-18 rhostar = ( density * 0.055508 ) * pow(omega, 3) * Na mustarsq = pow(mu, 2) / ( k * ( temperature + 273.15 ) * pow(omega, 3) ) y = ( 4 * pi / 9 ) * rhostar * mustarsq f1 = 0.4341 * pow(rhostar, 2) f2 = - ( 0.05 + 0.75 * pow(rhostar, 3) ) f3 = - 0.026 * pow(rhostar, 2) + 0.173 * pow(rhostar, 4) fn_return_value = ( ( 3 * y ) / ( 1 - f1 * y ) ) * ( 1 + ( 1 - f1 ) * y + f2 * ( y * y ) + f3 * ( y * y * y ) ) + 1 elif (select_variable_3 == 3): #Values for N_k N_k = {} N_k[0] = 0.978224486826 N_k[1] = - 0.957771379375 N_k[2] = 0.237511794148 N_k[3] = 0.714692224396 N_k[4] = - 0.298217036956 N_k[5] = - 0.108863472196 N_k[6] = 0.0949327488264 N_k[7] = - 0.00980469816509 N_k[8] = 0.000016516763497 N_k[9] = 9.37359795772E-05 N_k[10] = - 1.2317921872E-10 N_k[11] = 0.00196096504426 #Values for i_k i_k = {} i_k[0] = 1 i_k[1] = 1 i_k[2] = 1 i_k[3] = 2 i_k[4] = 3 i_k[5] = 3 i_k[6] = 4 i_k[7] = 5 i_k[8] = 6 i_k[9] = 7 i_k[10] = 10 #Values for j_k j_k = {} j_k[0] = 0.25 j_k[1] = 1 j_k[2] = 2.5 j_k[3] = 1.5 j_k[4] = 1.5 j_k[5] = 2.5 j_k[6] = 2 j_k[7] = 2 j_k[8] = 5 j_k[9] = 0.5 j_k[10] = 10 avogadro = 6.0221367E+23 dipole = 6.138E-30 epsilon_o = 8.8541878176204E-12 boltzmann = 1.380658E-23 alpha = 1.636E-40 density_c = 17873.728 T_c = 647.096 #Convert density and temperature units density_molm3 = density * 0.055508 * 1000000 T_K = temperature + 273.15 #Defining the g equation g = 1 for ii in range(0, 11): g = g + N_k[ii] * pow(density_molm3 / density_c, np.double(i_k[ii])) * pow(T_c / T_K, np.double(j_k[ii])) g = g + N_k[11] * ( density_molm3 / density_c ) * pow(T_K / 228 - 1, - 1.2) #Defining the A, B, and C equations A = ( avogadro * pow(dipole, 2) * density_molm3 * g ) / ( epsilon_o * boltzmann * T_K ) B = ( avogadro * alpha * density_molm3 ) / ( 3 * epsilon_o ) C = 9 + 2 * A + 18 * B + A * A + 10 * A * B + 9 * B * B fn_return_value = ( 1 + A + 5 * B + np.sqrt(C) ) / ( 4 - 4 * B ) elif (select_variable_3 == 4): #Relevant parameters a1 = - 1.57637700752506E-03 a2 = 6.81028783422197E-02 a3 = 0.754875480393944 b1 = - 8.01665106535394E-05 b2 = - 6.87161761831994E-02 b3 = 4.74797272182151 A = a1 * temperature + a2 * np.sqrt(temperature) + a3 B = b1 * temperature + b2 * np.sqrt(temperature) + b3 fn_return_value = np.exp(B) * pow(density, np.double(A)) else: fn_return_value = 0 return fn_return_value
def calculateG(P, T, density)
-
Calculates the pressure and temperature dependent solvent function. This function should only be used for pressures less than 6 kb. —Input— P - The pressure to calculate at, in bars T - The temperature to calculate at, in celsius density - The density of water at which to calculate g at, in g/cm^3 —Output— Returns the value of the g function. If the density is greather than 1 g/cm^3, then zero is returned.
Expand source code
def calculateG(P, T, density): '''Calculates the pressure and temperature dependent solvent function. This function should only be used for pressures less than 6 kb. ---Input--- P - The pressure to calculate at, in bars T - The temperature to calculate at, in celsius density - The density of water at which to calculate g at, in g/cm^3 ---Output--- Returns the value of the g function. If the density is greather than 1 g/cm^3, then zero is returned.''' if density >= 1: fn_return_value = 0 else: a_g = - 2.037662 + 0.005747 * T - 0.000006557892 * T * T b_g = 6.107361 - 0.01074377 * T + 0.00001268348 * T * T #Calculates the difference function in the case where we need to calculate at Psat conditions if ( P <= 1000 and T >= 155 and T <= 355 ) : f = ( pow(( T - 155 ) / 300, 4.8) + 36.66666 * pow(( T - 155 ) / 300, np.double(16)) ) *( - 1.504956E-10 * pow(1000 - P, np.double(3)) + 5.017997E-14 * pow(1000 - P, np.double(4)) ) else: f = 0 fn_return_value = a_g * pow(1 - density, b_g) - f return fn_return_value
def calculateGibbsOfWater(pressure, temp, equation, densityEquation, Psat)
-
This function calculates the Gibbs Free Energy of Water. It can calculate with two equations. —Input—' pressure - The pressure to calculate the Gibbs Free Energy at, in bars temperature - The temperature to calculate the Gibbs Free Energy at, in Celsius equation - Determines which equation to use to calculate the Gibbs Free Energy, either Delaney & Helgeson (1978), corresonding to equation = 1, or simply integrating over the volume of water, corresponding to equation = 2 density Equation - Determines which equation to use to find the density, and thus the volume of water. Psat - Determines if the calculation should be done at Psat. —Output— Returns the Gibbs Free Energy of water in units of cal/mol. If a proper value for equation was not entered, zero is returned.
Expand source code
def calculateGibbsOfWater(pressure, temp, equation, densityEquation, Psat): '''This function calculates the Gibbs Free Energy of Water. It can calculate with two equations. ---Input---' pressure - The pressure to calculate the Gibbs Free Energy at, in bars temperature - The temperature to calculate the Gibbs Free Energy at, in Celsius equation - Determines which equation to use to calculate the Gibbs Free Energy, either Delaney & Helgeson (1978), corresonding to equation = 1, or simply integrating over the volume of water, corresponding to equation = 2 density Equation - Determines which equation to use to find the density, and thus the volume of water. Psat - Determines if the calculation should be done at Psat. ---Output--- Returns the Gibbs Free Energy of water in units of cal/mol. If a proper value for equation was not entered, zero is returned. ''' if Psat == True: #This equation models the Gibbs Free Energy of water as a function of temperature along the Psat curve. #It has an R^2 value of 0.9999999984518 as compared with Supcrt92 values. fn_return_value = - 2.72980941772081E-103 * pow(temp, np.double(40)) + 2.88918186300446E-25 * pow(temp, np.double(10)) + - 2.21891314234246E-08 * pow(temp, np.double(4)) + 3.0912103873633E-05 * pow(temp, np.double(3)) + - 3.20873264480928E-02 * pow(temp, np.double(2)) + - 15.169458452209 * temp + - 56289.0379433809 else: select_variable_2 = equation if (select_variable_2 == 1): coeff = {} coeff[0] = - 56130.073 coeff[1] = 0.38101798 coeff[2] = - 0.0000021167697 coeff[3] = 2.0266445E-11 coeff[4] = - 8.3225572E-17 coeff[5] = - 15.285559 coeff[6] = 0.0001375239 coeff[7] = - 1.5586868E-09 coeff[8] = 6.6329577E-15 coeff[9] = - 0.026092451 coeff[10] = 0.000000035988857 coeff[11] = - 2.7916588E-14 coeff[12] = 0.000017140501 coeff[13] = - 1.6860893E-11 coeff[14] = - 6.0126987E-09 gibbsFreeEnergy = 0 Count = 0 for j in range(0, 5): for k in range(0, 5 - j): temp = np.absolute(temp) gibbsFreeEnergy = gibbsFreeEnergy + coeff[Count] * pow((temp), np.double(j)) * pow(pressure, np.double(k)) Count = Count + 1 fn_return_value = gibbsFreeEnergy elif (select_variable_2 == 2): #then defines the gibbs free energy as the integral over the volume as a function of temperature. #We can only perform this calculation if we can use one of the two density equations included #in the code. If densityEquation equals three, then that implies the user chose to use custom #density values. Because this procedure requires integration over a range of densities, this #cannot be calculated if the user has custom density values. Therefore, this will just return zero. if ( densityEquation == 3 ) : fn_return_value = 0 #Gibbs Free Energy of water at 1 kb. This equation is a polynomial fit to data as a function of temperature. #It is valid in the range of 100 to 1000 C. temp = np.absolute(temp) GAtOneKb = 2.6880734E-09 *(temp * temp)*(temp*temp) + 0.00000063163061 * (temp * temp * temp) - 0.019372355 * ( temp * temp ) - 16.945093 * temp - 55769.287 if pressure < 1000: fn_return_value = 0 elif pressure == 1000: fn_return_value = GAtOneKb elif pressure > 1000: integral = 0 #Integral is sum of rectangles with this width. This function in effect limits the spacing #to 20 bars so that very small pressures do not have unreasonably small widths. Otherwise the width #is chosen such that there are always 500 steps in the numerical integration. This ensures that for very #high pressures, there are not a huge number of steps calculated which is very computationally taxing. if ( pressure - 1000 ) / 500 < 20: spacing = 20 else: spacing = ( pressure - 1000 ) / 500 for i in range(1000, pressure + 1, int(spacing)): #This integral determines the density only down to an error of 100 bars #rather than the standard of 0.01. This is done to save computational #time. Tests indicate this reduces the computation by about a half while #introducing little error from the standard of 0.01. integral = integral + ( 18.01528 / DEWEquations.calculateDensity(i, temp, densityEquation, 100, False) / 41.84 ) * spacing fn_return_value = GAtOneKb + integral else: fn_return_value = 0 return fn_return_value
def calculateOmega(P, T, density, name, wref, Z)
-
This function calculates the born coefficient omega for aqueous species as a function of pressure and temeprature —Input— P - Pressure to calculate at, in bars T - Temperature to calculate at, in Celsius density - Density of water to calculate omega at, in g/cm^3. This could be calculated from P and T, but it is used as an input parameter to save on calculation time. name - The name of the species this is being calculated for. wref - The value of omega at standard pressure and temperature, in units of cal/mol. This should not be the value generally given as omega*1E-5, but rather the actual value of omega. Z - The charge of the species —Output— Returns the value of omega at the input P and T. If Z is zero, the wprtr value is used. The value returned is in units of cal/mol and NOT multiplied by 10^-5.
Expand source code
def calculateOmega(P, T, density, name, wref, Z): '''This function calculates the born coefficient omega for aqueous species as a function of pressure and temeprature ---Input--- P - Pressure to calculate at, in bars T - Temperature to calculate at, in Celsius density - Density of water to calculate omega at, in g/cm^3. This could be calculated from P and T, but it is used as an input parameter to save on calculation time. name - The name of the species this is being calculated for. wref - The value of omega at standard pressure and temperature, in units of cal/mol. This should not be the value generally given as omega*1E-5, but rather the actual value of omega. Z - The charge of the species ---Output--- Returns the value of omega at the input P and T. If Z is zero, the wprtr value is used. The value returned is in units of cal/mol and NOT multiplied by 10^-5. ''' #If species is hydrogen, the species is neutral, or the pressure is above 6 kb, #this equation is not necessary because omega is very close to wref. if name == 'H+' or Z == 0 or P > 6000: fn_return_value = wref else: #These equations are given by Shock et al. (1992) eta = 166027 #Defines the electrostatic radius at reference pressure and temperature reref = Z * Z / ( wref / eta + Z / 3.082 ) #This represents the pressure and temperature dependent solvent function g = DEWEquations.calculateG(P, T, density) #Defines the electrostatic radius at the input P and T re = reref + np.abs(Z) * g fn_return_value = eta * ( Z * Z / re - Z / ( 3.082 + g ) ) return fn_return_value
def calculatePressure(density, temperature, equation)
-
Calculates the pressure of water as a function of density and temperature using one of two equation of states. —Input— density - The density to use in finding a pressure, in g/cm^3 temperature - The temperature to use in finding a pressure, in Celsius equation - The equation of state to use when calculating the pressure. equation = 1 corresponds to using Zhang & Duan (2005) equation = 2 corresponds to using Zhang & Duan (2009) —Output— Returns the pressure of water corresponding to the input density and temperature, in units of bars. If a proper value for the equation was not entered, zero is returned.
Expand source code
def calculatePressure(density, temperature, equation): '''Calculates the pressure of water as a function of density and temperature using one of two equation of states. ---Input--- density - The density to use in finding a pressure, in g/cm^3 temperature - The temperature to use in finding a pressure, in Celsius equation - The equation of state to use when calculating the pressure. equation = 1 corresponds to using Zhang & Duan (2005) equation = 2 corresponds to using Zhang & Duan (2009) ---Output--- Returns the pressure of water corresponding to the input density and temperature, in units of bars. If a proper value for the equation was not entered, zero is returned. ''' B = None C = None D = None E = None f = None g = None m = None m = np.double(18.01528) select_variable_0 = equation if (select_variable_0 == 1): ZD05_R = 83.144 ZD05_Vc = 55.9480373 ZD05_Tc = 647.25 TK = temperature + 273.15 Vr = m / density / ZD05_Vc Tr = TK / ZD05_Tc B = 0.349824207 - 2.91046273 / ( Tr * Tr ) + 2.00914688 / ( Tr * Tr * Tr ) C = 0.112819964 + 0.748997714 / ( Tr * Tr ) - 0.87320704 / ( Tr * Tr * Tr ) D = 0.0170609505 - 0.0146355822 / ( Tr * Tr ) + 0.0579768283 / ( Tr * Tr * Tr ) E = - 0.000841246372 + 0.00495186474 / ( Tr * Tr ) - 0.00916248538 / ( Tr * Tr * Tr ) f = - 0.100358152 / Tr g = np.double(- 0.00182674744 * Tr) delta = 1 + B / Vr + C / ( Vr * Vr ) + D / pow(Vr, np.double(4)) + E / pow(Vr, np.double(5)) + ( f / ( Vr * Vr ) + g / pow(Vr, np.double(4)) ) * np.exp(- 0.0105999998 / ( Vr * Vr )) fn_return_value = ZD05_R * TK * density * delta / m elif (select_variable_0 == 2): ZD09_R = 0.083145 #Constant equal to ZD09_epsilon / (3.0626 * ZD09_omega^3) ZD09_c1 = 6.971118009 #ZD09_epsilon = 510 'Lenard-Jones parameter in units of K #ZD09_omega = 2.88 'Lenard-Jones parameter in units of 1E-10 m #Prefactor calculated from 1000 * pow(ZD09_omega / 3.691, 3) dm = 475.05656886 * density #Prefactor calculated from 0.001 * pow(3.691 / ZD09_omega, 3) Vm = 0.0021050125 * ( m / density ) #Prefactor calculated from 154 / ZD09_epsilon Tm = 0.3019607843 * ( temperature + 273.15 ) B = 0.029517729893 - 6337.56452413 / ( Tm * Tm ) - 275265.428882 / ( Tm * Tm * Tm ) C = 0.00129128089283 - 145.797416153 / ( Tm * Tm ) + 76593.8947237 / ( Tm * Tm * Tm ) D = 2.58661493537E-06 + 0.52126532146 / ( Tm * Tm ) - 139.839523753 / ( Tm * Tm * Tm ) E = - 2.36335007175E-08 + 0.00535026383543 / ( Tm * Tm ) - 0.27110649951 / ( Tm * Tm * Tm ) f = 25038.7836486 / ( Tm * Tm * Tm ) delta = 1 + B / Vm + C / ( Vm * Vm ) + D / pow(Vm, 4) + E / pow(Vm, 5) + f / ( Vm * Vm ) * ( 0.73226726041 + 0.015483335997 / ( Vm * Vm ) ) * np.exp(- 0.015483335997 / ( Vm * Vm )) Pm = ZD09_R * Tm * delta / Vm fn_return_value = Pm * ZD09_c1 else: fn_return_value = 0 return fn_return_value
def calculateQ(pressure, temperature, density, densityEquation, epsilonEquation, Psat)
-
This method calculates the Born Coefficient Q as (1/eps^2)*(d(eps)/dP) - In other words the derivative of epsilon with respect to pressure, divided by epsilon squared —Input— pressure - The pressure to calculate Q at, in bars temperature - The temperature to calculate Q at, in Celsius density - The density at the input pressure and temperature, input simply to save time, in g/cm^3 denistyEquation - The density equation to use in calculating the density of water. epsilonEquation - The epsilon equation to use in calculating epsilon. Psat - Determines if the calculation should be done at Psat. —Output— Outputs the value of Q in units of bar^-1 Calculates the pressure and temperature dependent solvent function. This function should only be used for pressures less than 6 kb. —Input— P - The pressure to calculate at, in bars T - The temperature to calculate at, in celsius density - The density of water at which to calculate g at, in g/cm^3 —Output— Returns the value of the g function. If the density is greather than 1 g/cm^3, then zero is returned.
Expand source code
def calculateQ(pressure, temperature, density, densityEquation, epsilonEquation, Psat): '''This method calculates the Born Coefficient Q as (1/eps^2)*(d(eps)/dP) - In other words the derivative of epsilon with respect to pressure, divided by epsilon squared ---Input--- pressure - The pressure to calculate Q at, in bars temperature - The temperature to calculate Q at, in Celsius density - The density at the input pressure and temperature, input simply to save time, in g/cm^3 denistyEquation - The density equation to use in calculating the density of water. epsilonEquation - The epsilon equation to use in calculating epsilon. Psat - Determines if the calculation should be done at Psat. ---Output--- Outputs the value of Q in units of bar^-1 Calculates the pressure and temperature dependent solvent function. This function should only be used for pressures less than 6 kb. ---Input--- P - The pressure to calculate at, in bars T - The temperature to calculate at, in celsius density - The density of water at which to calculate g at, in g/cm^3 ---Output--- Returns the value of the g function. If the density is greather than 1 g/cm^3, then zero is returned. ''' if Psat == True: #This equation models the Q Born Coefficent as a function of temperature along the Psat curve. #It has an R^2 value of 0.99999998602 as compared with values listed in Shock et al. (1992). fn_return_value = ( 1.99258688758345E-49 * pow(temperature, np.double(20)) + - 4.43690270750774E-14 * pow(temperature, np.double(6)) + 4.29110215680165E-11 * pow(temperature, np.double(5)) + - 1.07146606081182E-08 * pow(temperature, np.double(4)) + 1.09982931856694E-06 * pow(temperature, np.double(3)) + 9.60705240954956E-06 * pow(temperature, np.double(2)) + 0.642579832259358 ) * 0.000001 else: #This commented section is the code to calculate the value of Q using a finite difference derivative. #------------------------- # Dim epsilon, delta, epsilonPlusDelta As Double # # delta = 1 # # epsilon = DEWEquations.calculateEpsilon(density, temperature, epsilonEquation, False) # # epsilonPlusDelta = DEWEquations.calculateEpsilon(calculateDensity(pressure + delta, temperature, densityEquation, 0.01, False), temperature, epsilonEquation, False) # # calculateQ = (1 / pow(np.double(epsilon), 2)) * ((epsilonPlusDelta - epsilon) / delta) #------------------------- eps = DEWEquations.calculateEpsilon(density, temperature, epsilonEquation, Psat) depsdrho = DEWEquations.calculate_depsdrho(density, temperature, epsilonEquation) drhodP = DEWEquations.calculate_drhodP(density, temperature, densityEquation) fn_return_value = depsdrho * drhodP / ( eps * eps ) return fn_return_value
def calculate_depsdrho(density, temperature, equation)
-
Calculates the partial derivative of the dielectric constant (epsilon) with respect to density, i.e. (d(eps)/d(rho))_T This is done using one of four possible equations —Input— density - The density of water to calculate with, in g/cm^3 temperature - The temperature to calculate with, in Celsius equation - Determines which equation should be used to calculate the derivative equation = 1 corresponds to using Johnson & Norton (1991), the equation used in Supcrt equation = 2 corresponds to using Franck (1990) equation = 3 corresponds to using Fernandez (1997) equation = 4 corredponds to using the Power Function. This is an equation derived by Dimitri Sverjensky and Brandon Harison at Johns Hopkins University. —Output— Returns the partial derivative of the dielectric constant with respect to density in units of cm^3/g. If a proper value for equation was not entered, zero is returned.
Expand source code
def calculate_depsdrho(density, temperature, equation): '''Calculates the partial derivative of the dielectric constant (epsilon) with respect to density, i.e. (d(eps)/d(rho))_T This is done using one of four possible equations ---Input--- density - The density of water to calculate with, in g/cm^3 temperature - The temperature to calculate with, in Celsius equation - Determines which equation should be used to calculate the derivative equation = 1 corresponds to using Johnson & Norton (1991), the equation used in Supcrt equation = 2 corresponds to using Franck (1990) equation = 3 corresponds to using Fernandez (1997) equation = 4 corredponds to using the Power Function. This is an equation derived by Dimitri Sverjensky and Brandon Harison at Johns Hopkins University. ---Output--- Returns the partial derivative of the dielectric constant with respect to density in units of cm^3/g. If a proper value for equation was not entered, zero is returned. ''' select_variable_4 = equation if (select_variable_4 == 1): T_hat = ( temperature + 273.15 ) / 298.15 k1 = 14.70333593 / T_hat k2 = 212.8462733 / T_hat - 115.4445173 + 19.55210915 * T_hat k3 = - 83.3034798 / T_hat + 32.13240048 * T_hat - 6.69409865 * ( T_hat * T_hat ) k4 = - 37.86202045 / ( T_hat * T_hat ) + 68.87359646 / T_hat - 27.29401652 fn_return_value = k1 + 2 * k2 * density + 3 * k3 * pow(density, 2) + 4 * k4 * pow(density, 3) elif (select_variable_4 == 2): pi = 3.14159265358979 omega = 0.0000000268 k = 1.380648E-16 Na = 6.022E+23 mu = 2.33E-18 density = density * 0.055508 cc = pow(omega, 3) * Na rhostar = density * cc mustarsq = pow(mu, 2) / ( k * ( temperature + 273.15 ) * pow(omega, 3) ) y = ( 4 * pi / 9 ) * rhostar * mustarsq f1 = 0.4341 * pow(rhostar, 2) f2 = - ( 0.05 + 0.75 * pow(rhostar, 3) ) f3 = - 0.026 * pow(rhostar, 2) + 0.173 * pow(rhostar, 4) dydrho = ( 4 * pi / 9 ) * mustarsq * cc df1drho = 2 * 0.4341 * pow(cc, 2) * density df2drho = - 3 * 0.75 * pow(cc, 3) * pow(density, 2) df3drho = - 2 * 0.026 * pow(cc, 2) * density + 4 * 0.173 * pow(cc, 4) * pow(density, 3) eps = ( ( 3 * y ) / ( 1 - f1 * y ) ) * ( 1 + ( 1 - f1 ) * y + f2 * ( y * y ) + f3 * ( y * y * y ) ) + 1 #The 0.055508 value converts the units from cm^3/mol to cm^3/g fn_return_value = 0.05508 * ( ( ( dydrho + pow(y, 2) * df1drho ) / ( 1 - f1 * y ) ) * ( eps - 1 ) / y + ( ( 3 * y ) / ( 1 - f1 * y ) ) * ( - df1drho * y + df2drho * pow(y, 2) + df3drho * pow(y, 3) + ( 1 - f1 + 2 * f2 * y + 3 * f3 * y * y ) * dydrho ) ) elif (select_variable_4 == 3): #Values for N_k N_k = {} N_k[0] = 0.978224486826 N_k[1] = - 0.957771379375 N_k[2] = 0.237511794148 N_k[3] = 0.714692224396 N_k[4] = - 0.298217036956 N_k[5] = - 0.108863472196 N_k[6] = 0.0949327488264 N_k[7] = - 0.00980469816509 N_k[8] = 0.000016516763497 N_k[9] = 9.37359795772E-05 N_k[10] = - 1.2317921872E-10 N_k[11] = 0.00196096504426 #Values for i_k i_k = {} i_k[0] = 1 i_k[1] = 1 i_k[2] = 1 i_k[3] = 2 i_k[4] = 3 i_k[5] = 3 i_k[6] = 4 i_k[7] = 5 i_k[8] = 6 i_k[9] = 7 i_k[10] = 10 #Values for j_k j_k = {} j_k[0] = 0.25 j_k[1] = 1 j_k[2] = 2.5 j_k[3] = 1.5 j_k[4] = 1.5 j_k[5] = 2.5 j_k[6] = 2 j_k[7] = 2 j_k[8] = 5 j_k[9] = 0.5 j_k[10] = 10 avogadro = 6.0221367E+23 dipole = 6.138E-30 epsilon_o = 8.8541878176204E-12 boltzmann = 1.380658E-23 alpha = 1.636E-40 density_c = 17873.728 T_c = 647.096 #Convert density and temperature units density_molm3 = density * 0.055508 * 1000000 T_K = temperature + 273.15 #Defining the g equation g = 1 for ii in range(0, 11): g = g + N_k[ii] * pow(density_molm3 / density_c, np.double(i_k[ii])) * pow(T_c / T_K, np.double(j_k[ii])) g = g + N_k[11] * ( density_molm3 / density_c ) * pow(T_K / 228 - 1, - 1.2) #Defining the dgdrho equation dgdrho = 0 for ii in range(0, 11): dgdrho = dgdrho + i_k[ii] * N_k[ii] * ( pow(density_molm3, np.double(i_k[ii] - 1)) / pow(density_c, np.double(i_k[ii])) ) * pow(T_c / T_K, np.double(j_k[ii])) dgdrho = dgdrho + ( N_k[11] / density_c ) * pow(T_K / 228 - 1, - 1.2) #Defining the A, B, and C equations A = ( avogadro * pow(dipole, 2) * density_molm3 * g ) / ( epsilon_o * boltzmann * T_K ) B = ( avogadro * alpha * density_molm3 ) / ( 3 * epsilon_o ) C = 9 + 2 * A + 18 * B + A * A + 10 * A * B + 9 * B * B #Defining the derivatives and epsilon dAdrho = A / density_molm3 + ( A / g ) * dgdrho dBdrho = B / density_molm3 dCdrho = 2 * dAdrho + 18 * dBdrho + 2 * A * dAdrho + 10 * ( dAdrho * B + A * dBdrho ) + 18 * B * dBdrho eps = ( 1 + A + 5 * B + pow(np.double(C), 0.5)) / ( 4 - 4 * B ) #The 55508 value converts the units from m^3/mol to cm^3/g fn_return_value = 55508 * ( 1 / ( 4 - 4 * B ) ) * ( 4 * dBdrho * eps + dAdrho + 5 * dBdrho + 0.5 * pow(np.double(C), - 0.5) * dCdrho ) elif (select_variable_4 == 4): #Relevant parameters a1 = - 1.57637700752506E-03 a2 = 6.81028783422197E-02 a3 = 0.754875480393944 b1 = - 8.01665106535394E-05 b2 = - 6.87161761831994E-02 b3 = 4.74797272182151 A = a1 * temperature + a2 * np.sqrt(temperature) + a3 B = b1 * temperature + b2 * np.sqrt(temperature) + b3 fn_return_value = A * np.exp(B) * pow(density, A - 1) else: fn_return_value = 0 return fn_return_value
def calculate_dgdP(P, T, density, g, equation, Psat=True)
-
Calculates the pressure derivative of the pressure and temperature dependent solvent function. This function should only be used for pressures less than 6 kb. —Input— P - The pressure to calculate at, in bars T - The temperature to calculate at, in celsius density - The density of water at which to calculate g at, in g/cm^3 g - The value of the g solvent function at the input P and T equation - Determines which equation to use in calculating the derivative of density with respect to pressure equation = 1 corresponds to Zhang & Duan (2005) equation = 1 corresponds to Zhang & Duan (2009) Psat - Determines if the calculation should be done along the Psat curve. In this case there is no equation for drhodP and a polynomial fit to data from Shock et al. (1992) is used. —Output— Returns the pressure derivative of the g function. If the density is greather than 1 g/cm^3, then zero is returned.
Expand source code
def calculate_dgdP(P, T, density, g, equation, Psat = True): '''Calculates the pressure derivative of the pressure and temperature dependent solvent function. This function should only be used for pressures less than 6 kb. ---Input--- P - The pressure to calculate at, in bars T - The temperature to calculate at, in celsius density - The density of water at which to calculate g at, in g/cm^3 g - The value of the g solvent function at the input P and T equation - Determines which equation to use in calculating the derivative of density with respect to pressure equation = 1 corresponds to Zhang & Duan (2005) equation = 1 corresponds to Zhang & Duan (2009) Psat - Determines if the calculation should be done along the Psat curve. In this case there is no equation for drhodP and a polynomial fit to data from Shock et al. (1992) is used. ---Output--- Returns the pressure derivative of the g function. If the density is greather than 1 g/cm^3, then zero is returned. ''' if Psat == True: #This equation models the derivative of the g solvent function with respect to pressure and #as a function of temperature along the Psat curve. #It has an R^2 value of 0.99995027718 as compared with values listed in Shock et al. (1992). #Particular care was taken to properly model the values at low temperatures which is why this #function not simply a polynomial if T < 0.01: fn_return_value = 0 else: fn_return_value = np.exp(1.37105493109451E-10 * pow(np.log(T), np.double(15)) + - 1.43605469318795E-06 * pow(np.log(T), np.double(10)) + 26.2649453651117 * np.log(T) + - 125.108856715714) * 0.000001 else: if density >= 1: fn_return_value = 0 else: b_g = 6.107361 - 0.01074377 * T + 0.00001268348 * T * T #Calculates the difference function in the case where we need to calculate at Psat conditions if ( P <= 1000 and T >= 155 and T <= 355 ) : dfdP = - ( pow(( T - 155 ) / 300, 4.8) + 36.66666 * pow(( T - 155 ) / 300, 16) ) * ( 3 * - 1.504956E-10 * pow(1000 - P, 2) + 4 * 5.017997E-14 * pow(1000 - P, 3) ) else: dfdP = 0 fn_return_value = - b_g * DEWEquations.calculate_drhodP(density, T, equation) * g / ( 1 - density ) - dfdP return fn_return_value
def calculate_domegadP(P, T, density, name, wref, Z, densityEquation, Psat)
-
This function calculates the derivative of the born coefficient omega with respect to pressure for aqueous species as a function of pressure and temeprature —Input— P - Pressure to calculate at, in bars T - Temperature to calculate at, in Celsius density - Density of water to calculate omega at, in g/cm^3. This could be calculated from P and T, but it is used as an input parameter to save on calculation time. name - The name of the species this is being calculated for. wref - The value of omega at standard pressure and temperature, in units of cal/mol. This should not be the value generally given as omega*1E-5, but rather the actual value of omega. Z - The charge of the species densityEquation - Determines which equation to use in calculating the derivative of density with respect to pressure. This is passed direction to calculate_dgdP equation = 1 corresponds to Zhang & Duan (2005) equation = 1 corresponds to Zhang & Duan (2009) Psat - Determines if the calculation should be done along the Psat curve. In this case there is no equation for drhodP and a polynomial fit to data from Shock et al. (1992) is used. —Output— Returns the value of the derivative of omega with respect to pressure at the input P and T. If Z is zero, then the derivative is zero. The value returned is in units of cal/mol/bar
Expand source code
def calculate_domegadP(P, T, density, name, wref, Z, densityEquation, Psat): '''This function calculates the derivative of the born coefficient omega with respect to pressure for aqueous species as a function of pressure and temeprature ---Input--- P - Pressure to calculate at, in bars T - Temperature to calculate at, in Celsius density - Density of water to calculate omega at, in g/cm^3. This could be calculated from P and T, but it is used as an input parameter to save on calculation time. name - The name of the species this is being calculated for. wref - The value of omega at standard pressure and temperature, in units of cal/mol. This should not be the value generally given as omega*1E-5, but rather the actual value of omega. Z - The charge of the species densityEquation - Determines which equation to use in calculating the derivative of density with respect to pressure. This is passed direction to calculate_dgdP equation = 1 corresponds to Zhang & Duan (2005) equation = 1 corresponds to Zhang & Duan (2009) Psat - Determines if the calculation should be done along the Psat curve. In this case there is no equation for drhodP and a polynomial fit to data from Shock et al. (1992) is used. ---Output--- Returns the value of the derivative of omega with respect to pressure at the input P and T. If Z is zero, then the derivative is zero. The value returned is in units of cal/mol/bar ''' #If species is hydrogen, the species is neutral, or the pressure is above 6 kb, #this equation is not necessary because omega is very close to wref. if name == 'H+' or Z == 0 or P > 6000: fn_return_value = 0 else: #These equations are given by Shock et al. (1992) eta = 166027 #Defines the electrostatic radius at reference pressure and temperature reref = Z * Z / ( wref / eta + Z / 3.082 ) #This represents the pressure and temperature dependent solvent function and its derivative g = DEWEquations.calculateG(P, T, density) dgdP = DEWEquations.calculate_dgdP(P, T, density, g, densityEquation, Psat) #Defines the electrostatic radius at the input P and T re = reref + np.absolute(Z) * g fn_return_value = - eta * ( np.absolute(Z * Z * Z) / pow(re, 2) - Z / pow(3.082 + g, 2) ) * dgdP return fn_return_value
def calculate_drhodP(density, temperature, equation)
-
Calculates the partial derivative of density with respect to pressure, i.e. (d(rho)/dP)_T This is done using one of two equations of state for water. —Input— density - The density of water, in g/cm^3 temperature - The temperature of water, in Celsius equation - The equation of state to use when calculating the pressure. equation = 1 corresponds to using Zhang & Duan (2005) equation = 2 corresponds to using Zhang & Duan (2009) —Output— Returns the partial derivative of density with respect to pressure of water corresponding to the input density and temperature, in units of g^3/cm^3/bar. If a proper value for the equation was not entered, zero is returned.
Expand source code
def calculate_drhodP(density, temperature, equation): '''Calculates the partial derivative of density with respect to pressure, i.e. (d(rho)/dP)_T This is done using one of two equations of state for water. ---Input--- density - The density of water, in g/cm^3 temperature - The temperature of water, in Celsius equation - The equation of state to use when calculating the pressure. equation = 1 corresponds to using Zhang & Duan (2005) equation = 2 corresponds to using Zhang & Duan (2009) ---Output--- Returns the partial derivative of density with respect to pressure of water corresponding to the input density and temperature, in units of g^3/cm^3/bar. If a proper value for the equation was not entered, zero is returned. ''' B = None C = None D = None E = None f = None g = None m = None m = np.double(18.01528) select_variable_1 = equation if (select_variable_1 == 1): ZD05_R = 83.144 ZD05_Vc = 55.9480373 ZD05_Tc = 647.25 TK = np.double(temperature + 273.15) Tr = TK / ZD05_Tc cc = ZD05_Vc / m Vr = m / ( density * ZD05_Vc ) B = 0.349824207 - 2.91046273 / ( Tr * Tr ) + 2.00914688 / ( Tr * Tr * Tr ) C = 0.112819964 + 0.748997714 / ( Tr * Tr ) - 0.87320704 / ( Tr * Tr * Tr ) D = 0.0170609505 - 0.0146355822 / ( Tr * Tr ) + 0.0579768283 / ( Tr * Tr * Tr ) E = - 0.000841246372 + 0.00495186474 / ( Tr * Tr ) - 0.00916248538 / ( Tr * Tr * Tr ) f = - 0.100358152 / Tr ##### # This value has been edited to be consistent with Mark Ghiorso's objective-C version of DEW and the original Zhang and Duan 2005 paper, # although it is incosistent with the Excel-implemented DEW Model g = np.double(- 0.00182674744 * Tr) ######## delta = 1 + B / Vr + C / ( Vr * Vr ) + D / pow(Vr, 4) + E / pow(Vr, 5) + ( f / ( Vr * Vr ) + g / pow(Vr, 4) ) * np.exp(- 0.0105999998 / pow(Vr, 2)) kappa = B * cc + 2 * C * ( cc * cc ) * density + 4 * D * pow(cc, 4) * pow(density, 3) + 5 * E * pow(cc, 5) * pow(density, 4) + ( 2 * f * ( cc * cc ) * density + 4 * g * pow(cc, 4) * pow(density, 3) - ( f / ( Vr * Vr ) + g / pow(Vr, 4) ) * ( 2 * 0.0105999998 * ( cc * cc ) * density ) ) * np.exp(- 0.0105999998 / ( Vr * Vr )) fn_return_value = m / ( ZD05_R * TK * ( delta + density * kappa ) ) elif (select_variable_1 == 2): ZD09_R = 0.083145 ZD09_c1 = 6.971118009 #ZD09_epsilon = 510 'Lenard-Jones parameter in units of K #ZD09_omega = 2.88 'Lenard-Jones parameter in units of 1E-10 m #Prefactor calculated from 1000 * pow(ZD09_omega / 3.691, 3) dm = 475.05656886 * density #Prefactor calculated from 0.001 * pow(3.691 / ZD09_omega, 3) Vm = 0.0021050125 * ( m / density ) #Prefactor calculated from 154 / ZD09_epsilon Tm = 0.3019607843 * ( temperature + 273.15 ) B = 0.029517729893 - 6337.56452413 / ( Tm * Tm ) - 275265.428882 / ( Tm * Tm * Tm ) C = 0.00129128089283 - 145.797416153 / ( Tm * Tm ) + 76593.8947237 / ( Tm * Tm * Tm ) D = 2.58661493537E-06 + 0.52126532146 / ( Tm * Tm ) - 139.839523753 / ( Tm * Tm * Tm ) E = - 2.36335007175E-08 + 0.00535026383543 / ( Tm * Tm ) - 0.27110649951 / ( Tm * Tm * Tm ) f = 25038.7836486 / ( Tm * Tm * Tm ) delta = 1 + B / Vm + C / ( Vm * Vm ) + D / pow(Vm, 4) + E / pow(Vm, 5) + f / ( Vm * Vm ) * ( 0.73226726041 + 0.015483335997 / ( Vm * Vm ) ) * np.exp(- 0.015483335997 / ( Vm * Vm )) kappa = B / m + 2 * C * dm / ( m * m ) + 4 * D * pow(dm, 3) / pow(m, 4) + 5 * E * pow(dm, 4) / pow(m, 5) + ( 2 * f * dm / ( m * m ) * ( 0.73226726041 + 0.015483335997 / ( Vm * Vm ) ) + f / pow(Vm, 2) * ( 1 - 0.73226726041 - 0.015483335997 / ( Vm * Vm ) ) * ( 2 * 0.015483335997 * dm / ( m * m ) ) ) * np.exp(- 0.015483335997 / ( Vm * Vm )) ##### Adding a comment here because I've made ZD09_c4 into ZD09 C_1 ####### ##### Original line###### #fn_return_value = ZD09_c1 * m / ( ZD09_c4 * ZD09_R * Tm * ( delta + dm * kappa ) ) fn_return_value = ZD09_c1 * m / ( ZD09_c1 * ZD09_R * Tm * ( delta + dm * kappa ) ) else: fn_return_value = 0 return fn_return_value