I was wondering if anyone knew how to find the values of A and B in Arrhenius equation (๐๐๐๐ =๐ด๐^(โ๐ต๐ ๐)) using Python. In this equation, ๐ is in Kelvin, and A has the unit of mL/min. We want to obtain a description of the rate as a function for temperature over the range from 0ยฐC to 35ยฐC, under the assumption that we can extrapolate.
Basically, we are trying to find out the activity of the yeast with temperature, but first we have to find A and B. I tried a couple curve fitting techniques but all have failed. My fit was a straight line and my numbers were really off.
This is the code/info given in the image:
import matplotlib.pyplot as plt
import numpy as np
import scipy as scipy
temperature = np.array([20,25,30,33,35,37,40,45]) # degrees C
prod_rate = np.array([6.9,9.9,21.2,26.1,32.9,30.4,18.8,18.5])/30 #mL/min
plt.plot(temperature,prod_rate,'ok')
plt.ylabel('Production (mL/min)')
plt.xlabel('Temperature (C)')
this was my best attempt:
import matplotlib.pyplot as plt
import numpy as np
import scipy as scipy
def arrhenius(T, A, B):
R = 8.314 # Gas constant, J/(molยทK)
return A * np.exp(-B / (R * T))
temperature = np.array([20,25,30,33,35,37,40,45]) # degrees C
prod_rate = np.array([6.9,9.9,21.2,26.1,32.9,30.4,18.8,18.5])/30 #mL/min
plt.plot(temperature, prod_rate, 'ok')
plt.ylabel('Production (mL/min)')
plt.xlabel('Temperature (C)')
popt, pcov = curve_fit(arrhenius, temperature, prod_rate)
print(popt)
A_optimal, B_optimal = popt
fitted_curve = arrhenius(temperature, A_optimal, B_optimal)
plt.plot(temperature, prod_rate, 'ok', label='Data')
plt.plot(temperature, fitted_curve, '-r', label='Fitted Curve')
plt.ylabel('Production (mL/min)')
plt.xlabel('Temperature (ยฐC)')
plt.legend()
plt.show()
print("Optimal value for A:", A_optimal, "mL/min")
print("Optimal value for B:", B_optimal)
This was the image it gave me and the numbers I got:
here is the new graph with Kelvin instead of Celsius:
import matplotlib.pyplot as plt
import numpy as np
import scipy as scipy
from scipy.optimize import curve_fit
def arrhenius(T, A, B):
R = 8.314 # Gas constant, J/(molยทK)
return A * np.exp(-B / (R * T))
temperature = np.array([20,25,30,33,35,37,40,45])
temperature_K = temperature + 273.15 # degrees C
prod_rate = np.array([6.9,9.9,21.2,26.1,32.9,30.4,18.8,18.5])/30 #mL/min
plt.plot(temperature_K, prod_rate, 'ok')
plt.ylabel('Production (mL/min)')
plt.xlabel('Temperature (C)')
popt, pcov = curve_fit(arrhenius, temperature_K, prod_rate)
print(popt)
A_optimal, B_optimal = popt
fitted_curve = arrhenius(temperature_K, A_optimal, B_optimal)
plt.plot(temperature_K, prod_rate, 'ok', label='Data')
plt.plot(temperature_K, fitted_curve, '-r', label='Fitted Curve')
plt.ylabel('Production (mL/min)')
plt.xlabel('Temperature (ยฐC)')
plt.legend()
plt.show()
print("Optimal value for A:", A_optimal, "mL/min")
print("Optimal value for B:", B_optimal)
Let's assume that your experiment was done wrong. Choose a sub-array to fit, and do it in the logarithmic scale because the linear scales are massive. Do use Kelvin, not Celsius. Here I assume the units of A are arbitrary because the production rate's units have not been corrected.
import matplotlib.pyplot as plt
import numpy as np
# Gas constant, J/(molยทK); and 0C in K
from scipy.constants import R, zero_Celsius
from scipy.optimize import curve_fit
temperature_C = np.array((20, 25, 30, 33, 35, 37, 40, 45))
temperature_K = temperature_C + zero_Celsius
prod_rate_mL_min = np.array((6.9,9.9,21.2,26.1,32.9,30.4,18.8,18.5))/30 # mL/min
def arrhenius(T: np.ndarray, A: float, B: float) -> np.ndarray:
return A * np.exp(-B/R/T)
def arrhenius_log(T: np.ndarray, logA: float, B: float) -> np.ndarray:
return logA - B/R/T
# The data are garbage; cut off the last three points during fit
valid_end = -3
# Estimate calculation, partially based on experimental data
B0 = 80_000
logA0 = np.log(
prod_rate_mL_min[valid_end - 1]
) + B0/R/temperature_K[valid_end - 1]
p0 = logA0, B0
(logA, B), _ = curve_fit(
f=arrhenius_log, p0=p0,
xdata=temperature_K[:valid_end],
ydata=np.log(prod_rate_mL_min[:valid_end]),
)
# Keep A in log space for accuracy's sake
a_pow = np.floor(logA / np.log(10))
a_mantissa = np.exp(logA - a_pow*np.log(10))
print(f'A = {a_mantissa:.6f}e{a_pow:.0f}')
print(f'B = {B:.3f}')
fig, ax = plt.subplots()
ax.scatter(
temperature_C[:valid_end], prod_rate_mL_min[:valid_end],
label='experiment (OK)',
)
ax.scatter(
temperature_C[valid_end:], prod_rate_mL_min[valid_end:],
label='experiment (bad)',
)
T_hires = np.linspace(
start=temperature_K.min(),
stop=temperature_K.max(),
num=201,
)
ax.plot(
T_hires - zero_Celsius,
np.exp(arrhenius_log(T_hires, *p0)),
label='guess',
)
ax.plot(
T_hires - zero_Celsius,
arrhenius(
T=T_hires, A=a_mantissa * 10**a_pow, B=B,
),
label='fit',
)
ax.set_xlabel('T (C)')
ax.set_ylabel('Rate (mL/min)')
ax.legend()
plt.show()
A = 6.119210e13
B = 81109.535
Notice that in log space the expression is linear, so you can reduce to a computationally simpler linear fit that does not require estimates:
import numpy as np
# Gas constant, J/(molยทK); and 0C in K
from scipy.constants import R, zero_Celsius
temperature_C = np.array((20, 25, 30, 33, 35, 37, 40, 45))
temperature_K = temperature_C + zero_Celsius
prod_rate_mL_min = np.array((6.9,9.9,21.2,26.1,32.9,30.4,18.8,18.5))/30 # mL/min
# The data are garbage; cut off the last three points during fit
valid_end = -3
(logA, B), *_ = np.linalg.lstsq(
a=np.stack((
np.ones(temperature_K.size + valid_end),
-1/R/temperature_K[:valid_end],
), axis=1),
b=np.log(prod_rate_mL_min[:valid_end]),
rcond=None,
)
# Keep A in log space for accuracy's sake
a_pow = np.floor(logA / np.log(10))
a_mantissa = np.exp(logA - a_pow*np.log(10))
print(f'A = {a_mantissa:.6f}e{a_pow:.0f}')
print(f'B = {B:.3f}')