Skip to content

Commit 60ca0b7

Browse files
committed
add bloch_redfield_tensor
1 parent 596aa4c commit 60ca0b7

File tree

2 files changed

+309
-0
lines changed

2 files changed

+309
-0
lines changed

src/br.jl

Lines changed: 277 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,277 @@
1+
import QuantumToolbox: _spre, _spost, _sprepost, makeVal, getVal
2+
3+
@doc raw"""
4+
bloch_redfield_tensor(
5+
H::QuantumObject{Operator},
6+
a_ops::Union{AbstractVector, Tuple},
7+
c_ops::Union{AbstractVector, Tuple, Nothing}=nothing;
8+
sec_cutoff::Real=0.1,
9+
fock_basis::Union{Val,Bool}=Val(false)
10+
)
11+
12+
Calculates the Bloch-Redfield tensor ([`SuperOperator`](@ref)) for a system given a set of operators and corresponding spectral functions that describes the system's coupling to its environment.
13+
14+
## Arguments
15+
16+
- `H`: The system Hamiltonian. Must be an [`Operator`](@ref)
17+
- `a_ops`: Nested list with each element is a `Tuple` of operator-function pairs `(a_op, spectra)`, and the coupling [`Operator`](@ref) `a_op` must be hermitian with corresponding `spectra` being a `Function` of transition energy
18+
- `c_ops`: List of collapse operators corresponding to Lindblad dissipators
19+
- `sec_cutoff`: Cutoff for secular approximation. Use `-1` if secular approximation is not used when evaluating bath-coupling terms.
20+
- `fock_basis`: Whether to return the tensor in the input (fock) basis or the diagonalized (eigen) basis.
21+
22+
## Return
23+
24+
The return depends on `fock_basis`.
25+
26+
- `fock_basis=Val(true)`: return the Bloch-Redfield tensor (in the fock basis) only.
27+
- `fock_basis=Val(false)`: return the Bloch-Redfield tensor (in the eigen basis) along with the transformation matrix from eigen to fock basis.
28+
"""
29+
function bloch_redfield_tensor(
30+
H::QuantumObject{Operator},
31+
a_ops::Union{AbstractVector, Tuple},
32+
c_ops::Union{AbstractVector, Tuple, Nothing}=nothing;
33+
sec_cutoff::Real=0.1,
34+
fock_basis::Union{Val,Bool}=Val(false)
35+
)
36+
rst = eigenstates(H)
37+
U = QuantumObject(rst.vectors, Operator(), H.dimensions)
38+
sec_cutoff = float(sec_cutoff)
39+
40+
# in fock basis
41+
R0 = liouvillian(H, c_ops)
42+
43+
# set fock_basis=Val(false) and change basis together at the end
44+
R1 = 0
45+
if !isempty(a_ops)
46+
R1 += mapreduce(x -> _brterm(rst, x[1], x[2], sec_cutoff, Val(false)), +, a_ops)
47+
48+
# do (a_op, spectra)
49+
# _brterm(rst, a_op, spectra, sec_cutoff, Val(false))
50+
# end
51+
end
52+
53+
SU = sprepost(U, U') # transformation matrix from eigen basis back to fock basis
54+
if getVal(fock_basis)
55+
return R0 + SU * R1 * SU'
56+
else
57+
return SU' * R0 * SU + R1, U
58+
end
59+
end
60+
61+
62+
function brcrossterm(
63+
H::T, a_op::T, b_op::T, spectra::F; sec_cutoff::Real=0.1,
64+
fock_basis::Bool=false
65+
) where {T<:QuantumObject{Operator}, F<:Function}
66+
return brcrossterm(H, a_op, b_op, spectra, sec_cutoff, makeVal(fock_basis))
67+
end
68+
69+
function brcrossterm(
70+
H::T, a_op::T, b_op::T, spectra::F, sec_cutoff::Real, fock_basis::Val{true}
71+
) where {T<:QuantumObject{Operator}, F<:Function}
72+
rst = eigenstates(H)
73+
return _brcrossterm(rst, a_op, b_op, spectra, sec_cutoff, Val(true))
74+
end
75+
76+
function brcrossterm(
77+
H::T, a_op::T, b_op::T, spectra::F, sec_cutoff::Real, fock_basis::Val{false}
78+
) where {T<:QuantumObject{Operator}, F<:Function}
79+
rst = eigenstates(H)
80+
return _brcrossterm(rst, a_op, b_op, spectra, sec_cutoff, Val(false)), Qobj(rst.vectors, Operator(), rst.dimensions)
81+
end
82+
83+
function _brcrossterm(
84+
rst::EigsolveResult,
85+
a_op::T,
86+
b_op::T,
87+
spectra::F,
88+
sec_cutoff::Real,
89+
fock_basis::Union{Val{true},Val{false}}
90+
) where {T<:QuantumObject{Operator},F<:Function}
91+
92+
_check_br_spectra(spectra)
93+
94+
cutoff = (sec_cutoff == -1) ? Inf : sec_cutoff |> float
95+
U, N = rst.vectors, length(rst.values)
96+
97+
skew = @. rst.values - rst.values' |> real
98+
spectrum = spectra.(skew)
99+
100+
A_mat = U' * a_op.data * U
101+
B_mat = U' * b_op.data * U
102+
103+
m_cut = similar(A_mat)
104+
map!(x -> abs(x) < cutoff, m_cut, skew)
105+
106+
ac_term = (A_mat .* spectrum) * B_mat
107+
bd_term = A_mat * (B_mat .* trans(spectrum))
108+
ac_term .*= m_cut
109+
bd_term .*= m_cut
110+
111+
Id = I(N)
112+
vec_skew = vec(skew)
113+
M_cut = @. abs(vec_skew - vec_skew') < cutoff
114+
115+
out = 1/2 * (
116+
+ QuantumToolbox._sprepost(B_mat .* trans(spectrum), A_mat)
117+
+ QuantumToolbox._sprepost(B_mat, A_mat .* spectrum)
118+
- _spost(ac_term, Id)
119+
- QuantumToolbox._spre(bd_term, Id)
120+
) .* M_cut
121+
122+
if getVal(fock_basis)
123+
return QuantumObject(_sprepost(U, U') * out * _sprepost(U', U), SuperOperator(), rst.dimensions)
124+
else
125+
return QuantumObject(out, SuperOperator(), rst.dimensions)
126+
end
127+
end
128+
129+
@doc raw"""
130+
brterm(
131+
H::QuantumObject{Operator},
132+
a_op::QuantumObject{Operator},
133+
spectra::Function;
134+
sec_cutoff::Real=0.1,
135+
fock_basis::Union{Bool, Val}=Val(false)
136+
)
137+
138+
Calculates the contribution of one coupling operator to the Bloch-Redfield tensor.
139+
140+
## Argument
141+
142+
- `H`: The system Hamiltonian. Must be an [`Operator`](@ref)
143+
- `a_op`: The operator coupling to the environment. Must be hermitian.
144+
- `spectra`: The corresponding environment spectra as a `Function` of transition energy.
145+
- `sec_cutoff`: Cutoff for secular approximation. Use `-1` if secular approximation is not used when evaluating bath-coupling terms.
146+
- `fock_basis`: Whether to return the tensor in the input (fock) basis or the diagonalized (eigen) basis.
147+
148+
## Return
149+
150+
The return depends on `fock_basis`.
151+
152+
- `fock_basis=Val(true)`: return the Bloch-Redfield term (in the fock basis) only.
153+
- `fock_basis=Val(false)`: return the Bloch-Redfield term (in the eigen basis) along with the transformation matrix from eigen to fock basis.
154+
"""
155+
function brterm(
156+
H::QuantumObject{Operator},
157+
a_op::QuantumObject{Operator},
158+
spectra::Function;
159+
sec_cutoff::Real=0.1,
160+
fock_basis::Union{Bool, Val}=Val(false)
161+
)
162+
rst = eigenstates(H)
163+
term = _brterm(rst, a_op, spectra, sec_cutoff, makeVal(fock_basis))
164+
if getVal(fock_basis)
165+
return term
166+
else
167+
return term, Qobj(rst.vectors, Operator(), rst.dimensions)
168+
end
169+
end
170+
171+
function _brterm(
172+
rst::EigsolveResult,
173+
a_op::T,
174+
spectra::F,
175+
sec_cutoff::Real,
176+
fock_basis::Union{Val{true},Val{false}}
177+
) where {T<:QuantumObject{Operator},F<:Function}
178+
179+
_check_br_spectra(spectra)
180+
181+
U, N = rst.vectors, prod(rst.dimensions)
182+
183+
skew = @. rst.values - rst.values' |> real
184+
spectrum = spectra.(skew)
185+
186+
A_mat = U' * a_op.data * U
187+
188+
ac_term = (A_mat .* spectrum) * A_mat
189+
bd_term = A_mat * (A_mat .* trans(spectrum))
190+
191+
if sec_cutoff != -1
192+
m_cut = similar(skew)
193+
map!(x -> abs(x) < sec_cutoff, m_cut, skew)
194+
ac_term .*= m_cut
195+
bd_term .*= m_cut
196+
197+
Id = I(N)
198+
vec_skew = vec(skew)
199+
M_cut = @. abs(vec_skew - vec_skew') < sec_cutoff
200+
end
201+
202+
out = 0.5 * (
203+
+ QuantumToolbox._sprepost(A_mat .* trans(spectrum), A_mat)
204+
+ QuantumToolbox._sprepost(A_mat, A_mat .* spectrum)
205+
- _spost(ac_term, Id)
206+
- QuantumToolbox._spre(bd_term, Id)
207+
)
208+
209+
(sec_cutoff != -1) && (out .*= M_cut)
210+
211+
212+
if getVal(fock_basis)
213+
SU = _sprepost(U, U')
214+
return QuantumObject(SU * out * SU', SuperOperator(), rst.dimensions)
215+
else
216+
return QuantumObject(out, SuperOperator(), rst.dimensions)
217+
end
218+
end
219+
220+
221+
222+
@doc raw"""
223+
brmesolve(
224+
H::QuantumObject{Operator},
225+
ψ0::QuantumObject,
226+
tlist::AbstractVector,
227+
a_ops::Union{Nothing, AbstractVector, Tuple},
228+
c_ops::Union{Nothing, AbstractVector, Tuple}=nothing;
229+
sec_cutoff::Real=0.1,
230+
e_ops::Union{Nothing, AbstractVector}=nothing,
231+
kwargs...,
232+
)
233+
234+
Solves for the dynamics of a system using the Bloch-Redfield master equation, given an input Hamiltonian, Hermitian bath-coupling terms and their associated spectral functions, as well as possible Lindblad collapse operators.
235+
236+
## Arguments
237+
238+
- `H`: The system Hamiltonian. Must be an [`Operator`](@ref)
239+
- `ψ0`: Initial state of the system $|\psi(0)\rangle$. It can be either a [`Ket`](@ref), [`Operator`](@ref) or [`OperatorKet`](@ref).
240+
- `tlist`: List of times at which to save either the state or the expectation values of the system.
241+
- `a_ops`: Nested list with each element is a `Tuple` of operator-function pairs `(a_op, spectra)`, and the coupling [`Operator`](@ref) `a_op` must be hermitian with corresponding `spectra` being a `Function` of transition energy
242+
- `c_ops`: List of collapse operators corresponding to Lindblad dissipators
243+
- `sec_cutoff`: Cutoff for secular approximation. Use `-1` if secular approximation is not used when evaluating bath-coupling terms.
244+
- `e_ops`: List of operators for which to calculate expectation values. It can be either a `Vector` or a `Tuple`.
245+
- `kwargs`: Keyword arguments for [`mesolve`](@ref).
246+
247+
## Notes
248+
249+
- This function will automatically generate the [`bloch_redfield_tensor`](@ref) and solve the time evolution with [`mesolve`](@ref).
250+
251+
# Returns
252+
253+
- `sol::TimeEvolutionSol`: The solution of the time evolution. See also [`TimeEvolutionSol`](@ref)
254+
"""
255+
function brmesolve(
256+
H::QuantumObject{Operator},
257+
ψ0::QuantumObject,
258+
tlist::AbstractVector,
259+
a_ops::Union{Nothing, AbstractVector, Tuple},
260+
c_ops::Union{Nothing, AbstractVector, Tuple}=nothing;
261+
sec_cutoff::Real=0.1,
262+
e_ops::Union{Nothing, AbstractVector}=nothing,
263+
kwargs...,
264+
)
265+
266+
R = bloch_redfield_tensor(H, a_ops, c_ops; sec_cutoff=sec_cutoff, fock_basis=Val(true))
267+
268+
return mesolve(R, ψ0, tlist, nothing; e_ops=e_ops, kwargs...)
269+
end
270+
271+
function _check_br_spectra(f::Function)
272+
meths = methods(f, [Real])
273+
length(meths.ms) == 0 && throw(
274+
ArgumentError("The following function must accept one argument: `$(meths.mt.name)(ω)` with ω<:Real")
275+
)
276+
return nothing
277+
end

src/brtools.jl

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,35 @@
1+
function bloch_redfield_tensor(
2+
H::QuantumObject{Operator},
3+
a_ops::Union{AbstractVector, Tuple},
4+
c_ops::Union{AbstractVector, Tuple, Nothing}=nothing;
5+
sec_cutoff::Real=0.1,
6+
fock_basis::Union{Val,Bool}=Val(false)
7+
)
8+
rst = eigenstates(H)
9+
U = QuantumObject(rst.vectors, Operator(), H.dimensions)
10+
sec_cutoff = float(sec_cutoff)
11+
12+
# in fock basis
13+
R0 = liouvillian(H, c_ops)
14+
15+
# set fock_basis=Val(false) and change basis together at the end
16+
R1 = 0
17+
if !isempty(a_ops)
18+
R1 += mapreduce(x -> _brterm(rst, x[1], x[2], sec_cutoff, Val(false)), +, a_ops)
19+
20+
# do (a_op, spectra)
21+
# _brterm(rst, a_op, spectra, sec_cutoff, Val(false))
22+
# end
23+
end
24+
25+
SU = sprepost(U, U') # transformation matrix from eigen basis back to fock basis
26+
if getVal(fock_basis)
27+
return R0 + SU * R1 * SU'
28+
else
29+
return SU' * R0 * SU + R1, U
30+
end
31+
end
32+
133
function brterm(
234
H::QuantumObject{Operator},
335
a_op::QuantumObject{Operator},

0 commit comments

Comments
 (0)