def analytic_R0(Gamma_L, Gamma_R):
    return np.array([[Gamma_L**2 + Gamma_L*Gamma_R, -Gamma_R**2 - Gamma_L*Gamma_R],
                     [-Gamma_L**2 - Gamma_L*Gamma_R, Gamma_R**2 + Gamma_L*Gamma_R]]) / (Gamma_L + Gamma_R)**3

def zero_freq_noise(liouvillian, jump_liouvillian, sys_dim, stationary_state, dv_pops, Gamma_L, Gamma_R):
    J_1 = cs.differentiate_jump_matrix(jump_liouvillian)
    Q = np.eye(sys_dim**2) - np.outer(stationary_state, dv_pops)
    R0 = np.dot(Q, np.dot(la.pinv2(-liouvillian), Q)) #analytic_R0(Gamma_L, Gamma_R) # 
    
    noise = - cs.trace_density_vector(np.dot(cs.differentiate_jump_matrix(J_1), stationary_state), dv_pops) \
                        - 2. * cs.trace_density_vector(np.dot(np.dot(np.dot(J_1, R0), J_1), stationary_state), dv_pops)
    
    return noise

def analytic_F2(Gamma_L, Gamma_R):
    return (Gamma_L**2 + Gamma_R**2) / (Gamma_L + Gamma_R)**2

Gamma_L = 1.
Gamma_R = 2.
L = np.array([[-Gamma_L,Gamma_R],
              [Gamma_L,-Gamma_R]])
LJ = np.array([[0,Gamma_R],
              [0,0]])
dv_pops = np.array([1,1])
ss = utils.stationary_state(L, dv_pops)
print L
print analytic_R0(Gamma_L, Gamma_R)
print ss
print zero_freq_noise(L, LJ, np.sqrt(2), ss, dv_pops, Gamma_L, Gamma_R) / (Gamma_R*ss[-1])
print analytic_F2(Gamma_L, Gamma_R)
print '[Executing script...]'

# set up data
model = DimerVibModel() # model should be a subclass of DataModel

# first compare analytic and numerical zero-freq noise calculations
num_data_pts = 180
energy_gap_range = np.linspace(-2,3,num_data_pts)
F2 = np.zeros(num_data_pts)
#current = np.zeros(num_data_pts)

for i,E in enumerate(energy_gap_range):
    print 'calculating for energy gap ' + str(E)
    model.energy_gap = E
    L = model.liouvillian
    L_jump = model.jump_liouvillian
    dv_pops = np.eye(3*model.vib_basis_size).flatten()
    #dv_pops = np.delete(dv_pops, model.element_indices_to_remove, 0)
    
    dv = utils.stationary_state(L(0), dv_pops)
    #current[i] = cs.mean(L(0), L_jump(0), dv, dv_pops)
    F2[i] = cs.zero_freq_noise(L, dv_pops) / cs.mean(L(0), L_jump(0), dv, dv_pops)
    
np.savez('../../data/dimer_vib_energy_gap_zero_freq_F2_data.npz', energy_gap_range=energy_gap_range, F2=F2)

plt.plot(energy_gap_range, F2)
plt.show()

#easygui.msgbox('Script execution complete!', title='PyDev Alert')
print '[Script execution complete]'
import matplotlib.pyplot as plt
from vibration_counting_statistics.dimer_vib_model import DimerVibModel

freq_range = np.linspace(0, 2.5, 100)

model = DimerVibModel()
model.J = 0.2

F2 = np.zeros((3, freq_range.size))

model.mode_coupling = 0
L = model.liouvillian
L_dim = L().shape[0]
L_jump = model.jump_liouvillian
dm_pops = np.eye(np.sqrt(L_dim)).flatten()
ss = utils.stationary_state(L(), populations=dm_pops)
F2[0] = cs.second_order_fano_factor(L, L_jump, ss, freq_range, dm_pops)

model.mode_coupling = 0.3
mode_freq_vals = np.array([1., 2.])
for i,freq in enumerate(mode_freq_vals):
    model.omega = freq
    L = model.liouvillian
    L_dim = L().shape[0]
    L_jump = model.jump_liouvillian
    dm_pops = np.eye(np.sqrt(L_dim)).flatten()
    ss = utils.stationary_state(L(), populations=dm_pops)
    F2[i+1] = cs.second_order_fano_factor(L, L_jump, ss, freq_range, dm_pops)
    
np.savez('../../data/dimer_vib_finite_freq_F2_data.npz', freq_range=freq_range, F2=F2, mode_freq_vals=mode_freq_vals)

for i,v in enumerate(mode_dampings):
    print 'Calculations for v = ' + str(v)
    #model.mode_coupling = v
    #model.N = v
    model.vib_damping_rate = v
    
    temp_current = np.zeros(num_data_pts)
    #temp_current_cs = np.zeros(num_data_pts)
    
    for j,e in enumerate(energy_gap_range):
        model.energy_gap = e
        L = model.liouvillian()
        dm_pops = np.eye(3*model.vib_basis_size).flatten()
        ss_vec = utils.stationary_state(L, dm_pops)
        ss_mat = ss_vec.copy()
        ss_mat.shape = np.sqrt(ss_mat.shape[0]), np.sqrt(ss_mat.shape[0])
        ss_el = utils.partial_trace(ss_mat, utils.orthog_basis_set(model.vib_basis_size))
        temp_current[j] = model.Gamma_R * ss_el[2,2]
        #temp_current_cs[j] = cs.mean(L, model.jump_liouvillian(), ss_vec, dm_pops)
    
    current[i] = temp_current
    plt.plot(energy_gap_range, current[i], label=v)
    
#np.savez('../../data/dimer_vib_energy_gap_current_mode_coupling_data.npz', energy_gap_range=energy_gap_range, current=current, mode_couplings=mode_couplings)
#np.savez('../../data/dimer_vib_energy_gap_current_thermal_occupation_data.npz', energy_gap_range=energy_gap_range, current=current, thermal_occupations=thermal_occupations)
np.savez('../../data/dimer_vib_energy_gap_current_mode_damping_data.npz', energy_gap_range=energy_gap_range, current=current, mode_dampings=mode_dampings)

#plt.plot(energy_gap_range, current_cs)
plt.legend()