aboutsummaryrefslogtreecommitdiff
path: root/active_correction/scatter/2016.05.02 17-48-41 old delay space/src/H0.py
blob: e040203491b0ebc62390efbc6c5d71a77813bed9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
"""
@author: Dan

each instance of running this depends on a few initial conditions that have to 
be specified:
    out_group
    rho_0
    wa_central
    a_coupling
    gamma
    dipoles

so create a class where all these can describe the specific instance
"""

from NISE.lib.misc import *

def gen_w_0(wa_central, a_coupling):
    # convert nice system parameters into system vector indeces
    w_ag = wa_central
    w_2aa = w_ag - a_coupling
    w_2ag = 2*w_ag - a_coupling
    w_gg = 0.
    w_aa = w_gg
    return np.array( [w_gg, w_ag, -w_ag, w_aa, w_2ag, w_ag, w_2aa] )

def gen_Gamma_0(tau_ag, tau_aa, tau_2ag, tau_2aa):
    # same as gen_w_0, but for dephasing/relaxation times
    tau = np.array( [np.inf, tau_ag, tau_ag, 
                       tau_aa, tau_2ag, 
                       tau_ag, tau_2aa ] )
    Gamma = 1/tau
    return Gamma

class Omega:
    # record the propagator module used to evolve this hamiltonian
    propagator = 'rk'
    # phase cycling is not valuable in this hamiltonian
    pc = False
    # all attributes should have good initial guesses for parameters
    dm_vector = ['gg1','ag','ga','aa','2ag','ag2','2aa']
    #out_group = [[6,7]]#,[7]]
    out_group = [[5],[6]] # use this to separate alpha/gamma from beta for now
    #--------------------------Oscillator Properties--------------------------
    rho_0 = np.zeros((len(dm_vector)), dtype=np.complex64)
    rho_0[0] = 1.
    # 1S exciton central position
    wa_central = 7000.
    # exciton-exciton coupling
    a_coupling = 0. # cm-1
    # dephasing times, fs
    tau_ag  = 50.
    tau_aa  = np.inf #1./2000.
    tau_2aa = tau_ag
    tau_2ag = tau_ag
    # transition dipoles (a.u.)
    mu_ag =  1.0
    mu_2aa = 1.0 * mu_ag # HO approx (1.414) vs. uncorr. electron approx. (1.)
    # TOs sets which time-ordered pathways to include (1-6 for TrEE)
    # defaults to include all time-orderings included
    TOs = range(7)[1:] 
    #--------------------------Recorded attributes--------------------------
    out_vars = ['dm_vector', 'out_group', 'rho_0', 'mu_ag', 'mu_2aa', 
                'tau_ag', 'tau_aa', 'tau_2aa', 'tau_2ag',
                'wa_central', 'a_coupling', 'pc', 'propagator', 
                'TOs']
    #--------------------------Methods--------------------------
    def __init__(self, **kwargs):
        # inherit all class attributes unless kwargs has them; then use those 
        # values.  if kwargs is not an Omega attribute, it gets ignored
        # careful: don't redefine instance methods as class methods!
        for key, value in kwargs.items():
            if key in Omega.__dict__.keys(): 
                setattr(self, key, value)
            else:
                print 'did not recognize attribute {0}.  No assignment made'.format(key)
        # with this set, initialize parameter vectors
        self.w_0 = gen_w_0(self.wa_central, self.a_coupling)
        self.Gamma = gen_Gamma_0(self.tau_ag, self.tau_aa, self.tau_2ag, 
                                 self.tau_2aa)

    def o(self, efields, t, wl):
        # combine the two pulse permutations to produce one output array
        E1, E2, E3 = efields[0:3]
    
        out1 = self._gen_matrix(E1, E2, E3, t, wl, w1first = True)
        out2 = self._gen_matrix(E1, E2, E3, t, wl, w1first = False)

        return np.array([out1, out2], dtype=np.complex64)
    
    def _gen_matrix(self, E1, E2, E3, t, wl, w1first = True):
        """
        creates the coupling array given the input e-fields values for a specific time, t
        w1first selects whether w1 or w2p is the first interacting positive field
        
        Currently neglecting pathways where w2 and w3 require different frequencies
        (all TRIVE space, or DOVE on diagonal)
        
        Matrix formulated such that dephasing/relaxation is accounted for 
        outside of the matrix
        """
        wag  = wl[1]
        w2aa = wl[6]
        
        mu_ag = self.mu_ag
        mu_2aa = self.mu_2aa
    
        if w1first==True:
            first  = E1
            second = E3
        else:
            first  = E3
            second = E1

        O = np.zeros((len(t), len(wl), len(wl)), dtype=np.complex64)
        # from gg1
        O[:,1,0] =  mu_ag  * first  * rotor(-wag*t)
        if w1first and 3 in self.TOs:
            O[:,2,0] = -mu_ag  * E2     * rotor(wag*t)
        if not w1first and 5 in self.TOs:
            O[:,2,0] = -mu_ag  * E2     * rotor(wag*t)
        # from ag1
        #   to DQC
        if w1first and 2 in self.TOs:
            O[:,4,1] =  mu_2aa * second * rotor(-w2aa*t)
        if not w1first and 4 in self.TOs:
            O[:,4,1] =  mu_2aa * second * rotor(-w2aa*t)
        #   to pop
        if w1first and 1 in self.TOs:
            O[:,3,1] =  -mu_ag  * E2     * rotor(wag*t)
        if not w1first and 6 in self.TOs:
            O[:,3,1] =  -mu_ag  * E2     * rotor(wag*t)
        # from ga
        O[:,3,2] =  mu_ag  * first  * rotor(-wag*t)
        # from gg-aa
        O[:,5,3]  = -mu_ag  * second * rotor(-wag*t)      * mu_ag
        #   because of alpha and gamma pathways, count twice
        O[:,5,3] -= mu_ag  * second * rotor(-wag*t)      * mu_ag
        O[:,6,3]  = mu_2aa * second * rotor(-w2aa*t)     * mu_2aa
        # from 2ag
        O[:,6,4] =  mu_ag  * E2     * rotor(wag*t)       * mu_2aa
        O[:,5,4] = -mu_2aa * E2     * rotor(w2aa*t)      * mu_ag
        
        # make complex according to Liouville Equation
        O *= complex(0,0.5)
        
        # include coherence decay rates:
        for i in range(O.shape[-1]):
            O[:,i,i] = -self.Gamma[i]

        return O
    
    def ws(self, inhom_object):
        """
        creates the correspondence of oscillator energies to the state vector
        contains instructions for how energies change as subsets are changed
        """
        z = inhom_object.zeta
        
        wg = 0.0 + 0*z
        wa = z + self.wa_central
        w2a = 2*wa - self.a_coupling
    
        w_ag = wa - wg
        w_aa = wa - wa
        w_gg = wg - wg
        w_2ag = w2a - wg
        w_2aa = w2a - wa
        #array aggregates all frequencies to match state vectors
        w     = np.array( [w_gg, w_ag, -w_ag, w_aa, w_2ag, w_ag, w_2aa] )
        return w