In [1]:
%matplotlib inline
from ipywidgets import *
from IPython.display import display
import matplotlib.pyplot as plt
import numpy as np
from scipy.optimize import curve_fit
from util import *
from analysis import *
import fits
from plot import *
from plot3d import *
The sample dataset here contains experimental 2D-IR spectra taken by the Khalil group for the N-O stretch of sodium nitroprusside in a variety of solvents. These data are published in J Phys. Chem. A 2013, 117, 6234-6243. The following is a list of names and the abbreviations used here:
The SOLVENT_NAME variable below can be modified to load data from a different solvent.
In [2]:
SOLVENT_NAME = 'H2O'
data,w1,w3,tau2 = loadSolvent(SOLVENT_NAME)
In [3]:
%matplotlib
%matplotlib notebook
def update3d(TimePoint=1):
plt.close()
my_fig = plt.figure(figsize=(9,5),num=SOLVENT_NAME)
ax = surf3d(w1,w3,data[:,:,TimePoint],window_title=SOLVENT_NAME,ax_title='Time: '+str(tau2[TimePoint,0])+' fs',fig=my_fig,azim=azim,elev=elev)
azim = -50
elev = 30
interact_manual(update3d,TimePoint=IntSlider(min=0,max=len(tau2)))
Out[3]:
Single images at any time point can also be plotted.
In [4]:
TIME_FS = 0
%matplotlib inline
show_data(data, w1, w3, tau2, TIME_FS)
A set of 3 images at different time points can be plotted.
In [5]:
TIMES_FS = [0, 1500, 5000]
%matplotlib inline
show_3_data(data, w1, w3, tau2, TIMES_FS)
A variety of decompositions of the data are possible. Here the PCA is explored. Both the NORMALIZE and N_COMPONENTS variables can be changed to affect the behavior. NORMALIZE changes whether the images in the set are normalized prior to performing PCA. Without normalization, the first PCA component tends to reflect the peak intensity; with normalization, all of the components relate to the peak shape. N_COMPONENTS represents the number of components used in the decomposition.
In [6]:
NORMALIZE = True
N_COMPONENTS = 10
ANALYSIS_TYPE = 'pca' # 'pca', 'fa', or 'ica'
comp = get_components(data, normalize=NORMALIZE, n_comp=N_COMPONENTS, analysis_type=ANALYSIS_TYPE)
proj = get_projections(data, normalize=NORMALIZE, n_comp=N_COMPONENTS, analysis_type=ANALYSIS_TYPE)
%matplotlib inline
show_3_components(comp, w1, w3)
Individual components can also be visualized.
In [7]:
SELECTED_COMPONENT = 5
%matplotlib inline
show_component(comp, w1, w3, SELECTED_COMPONENT)
Three selected components can be visualized using the parameter COMPS, a list of components.
In [8]:
SELECTED_COMPONENTS = [1, 5, 10]
%matplotlib inline
show_3_components(comp, w1, w3, SELECTED_COMPONENTS)
In [9]:
SELECTED_COMPONENT = 1
%matplotlib inline
show_contribution(tau2,proj,SELECTED_COMPONENT)
show_component(comp,w1,w3,SELECTED_COMPONENT)
Now that we have time series data for each component we can use standard curve fits for linear and non-linear functions to estimate parameters such as time constants. The COMP parameter selects which component to use, and the T_SCALE parameter provides the units of the time (tau2) variable in fs. Thus a value of 1000 will correspond to ps. Adjusting this parameter is sometimes necessary to avoid underflow or overflow conditions. The p0 variable is used to specify the initial guess for a non-linear fit, and can be adjusted if the fit results are not satisfactory.
The list of non-linear fits available here are:
For the exponential decays, the relevant parameter is the characteristic decay time, given by 1/B. Single- and double-exponential fits of the first component's dynamics are shown below.
In [10]:
SELECTED_COMPONENT = 1
T_SCALE = 1000
p0 = np.abs(proj[0,SELECTED_COMPONENT-1] - proj[-1,SELECTED_COMPONENT-1]), 1, proj[-1,SELECTED_COMPONENT-1] # initial guess
popt, pcov = curve_fit(fits.my_exponential, tau2.ravel()*(1/T_SCALE), proj[:,SELECTED_COMPONENT-1], p0, maxfev=1000)
#print('A='+str(popt[0]))
#print('B='+str(popt[1]))
#print('C='+str(popt[2]))
#print()
print("Decay time: " + str(1/popt[1]) + " ps")
%matplotlib inline
show_exp_fit(tau2, proj, SELECTED_COMPONENT, popt, T_SCALE)
In [11]:
SELECTED_COMPONENT = 1
T_SCALE = 1000
p0 = 1, 1, 1, 1, 1 # initial guess
popt, pcov = curve_fit(fits.my_double_exp, tau2.ravel()*(1/T_SCALE), proj[:,SELECTED_COMPONENT-1], p0, maxfev=1000)
print("Decay time 1: " + str(1/popt[2]) + " ps")
print("Decay time 2: " + str(1/popt[3]) + " ps")
%matplotlib inline
show_exp_fit(tau2, proj, SELECTED_COMPONENT, popt, T_SCALE)
In [12]:
#reset the pyplot backend
%matplotlib
%matplotlib notebook
In [ ]: