|
| 1 | +export bloch_redfield_tensor, brterm, brmesolve |
| 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 | + isempty(a_ops) || (R1 += mapreduce(x -> _brterm(rst, x[1], x[2], sec_cutoff, Val(false)), +, a_ops)) |
| 46 | + |
| 47 | + SU = sprepost(U, U') # transformation matrix from eigen basis back to fock basis |
| 48 | + if getVal(fock_basis) |
| 49 | + return R0 + SU * R1 * SU' |
| 50 | + else |
| 51 | + return SU' * R0 * SU + R1, U |
| 52 | + end |
| 53 | +end |
| 54 | + |
| 55 | +@doc raw""" |
| 56 | + brterm( |
| 57 | + H::QuantumObject{Operator}, |
| 58 | + a_op::QuantumObject{Operator}, |
| 59 | + spectra::Function; |
| 60 | + sec_cutoff::Real=0.1, |
| 61 | + fock_basis::Union{Bool, Val}=Val(false) |
| 62 | + ) |
| 63 | +
|
| 64 | +Calculates the contribution of one coupling operator to the Bloch-Redfield tensor. |
| 65 | +
|
| 66 | +## Argument |
| 67 | +
|
| 68 | +- `H`: The system Hamiltonian. Must be an [`Operator`](@ref) |
| 69 | +- `a_op`: The operator coupling to the environment. Must be hermitian. |
| 70 | +- `spectra`: The corresponding environment spectra as a `Function` of transition energy. |
| 71 | +- `sec_cutoff`: Cutoff for secular approximation. Use `-1` if secular approximation is not used when evaluating bath-coupling terms. |
| 72 | +- `fock_basis`: Whether to return the tensor in the input (fock) basis or the diagonalized (eigen) basis. |
| 73 | +
|
| 74 | +## Return |
| 75 | +
|
| 76 | +The return depends on `fock_basis`. |
| 77 | +
|
| 78 | +- `fock_basis=Val(true)`: return the Bloch-Redfield term (in the fock basis) only. |
| 79 | +- `fock_basis=Val(false)`: return the Bloch-Redfield term (in the eigen basis) along with the transformation matrix from eigen to fock basis. |
| 80 | +""" |
| 81 | +function brterm( |
| 82 | + H::QuantumObject{Operator}, |
| 83 | + a_op::QuantumObject{Operator}, |
| 84 | + spectra::Function; |
| 85 | + sec_cutoff::Real = 0.1, |
| 86 | + fock_basis::Union{Bool,Val} = Val(false), |
| 87 | +) |
| 88 | + rst = eigenstates(H) |
| 89 | + term = _brterm(rst, a_op, spectra, sec_cutoff, makeVal(fock_basis)) |
| 90 | + if getVal(fock_basis) |
| 91 | + return term |
| 92 | + else |
| 93 | + return term, Qobj(rst.vectors, Operator(), rst.dimensions) |
| 94 | + end |
| 95 | +end |
| 96 | + |
| 97 | +function _brterm( |
| 98 | + rst::EigsolveResult, |
| 99 | + a_op::T, |
| 100 | + spectra::F, |
| 101 | + sec_cutoff::Real, |
| 102 | + fock_basis::Union{Val{true},Val{false}}, |
| 103 | +) where {T<:QuantumObject{Operator},F<:Function} |
| 104 | + _check_br_spectra(spectra) |
| 105 | + |
| 106 | + U = rst.vectors |
| 107 | + Id = I(prod(rst.dimensions)) |
| 108 | + |
| 109 | + skew = @. rst.values - rst.values' |> real |
| 110 | + spectrum = spectra.(skew) |
| 111 | + |
| 112 | + A_mat = U' * a_op.data * U |
| 113 | + |
| 114 | + ac_term = (A_mat .* spectrum) * A_mat |
| 115 | + bd_term = A_mat * (A_mat .* trans(spectrum)) |
| 116 | + |
| 117 | + if sec_cutoff != -1 |
| 118 | + m_cut = similar(skew) |
| 119 | + map!(x -> abs(x) < sec_cutoff, m_cut, skew) |
| 120 | + ac_term .*= m_cut |
| 121 | + bd_term .*= m_cut |
| 122 | + |
| 123 | + vec_skew = vec(skew) |
| 124 | + M_cut = @. abs(vec_skew - vec_skew') < sec_cutoff |
| 125 | + end |
| 126 | + |
| 127 | + out = |
| 128 | + 0.5 * ( |
| 129 | + + _sprepost(A_mat .* trans(spectrum), A_mat) + _sprepost(A_mat, A_mat .* spectrum) - _spost(ac_term, Id) - |
| 130 | + _spre(bd_term, Id) |
| 131 | + ) |
| 132 | + |
| 133 | + (sec_cutoff != -1) && (out .*= M_cut) |
| 134 | + |
| 135 | + if getVal(fock_basis) |
| 136 | + SU = _sprepost(U, U') |
| 137 | + return QuantumObject(SU * out * SU', SuperOperator(), rst.dimensions) |
| 138 | + else |
| 139 | + return QuantumObject(out, SuperOperator(), rst.dimensions) |
| 140 | + end |
| 141 | +end |
| 142 | + |
| 143 | +@doc raw""" |
| 144 | + brmesolve( |
| 145 | + H::QuantumObject{Operator}, |
| 146 | + ψ0::QuantumObject, |
| 147 | + tlist::AbstractVector, |
| 148 | + a_ops::Union{Nothing, AbstractVector, Tuple}, |
| 149 | + c_ops::Union{Nothing, AbstractVector, Tuple}=nothing; |
| 150 | + sec_cutoff::Real=0.1, |
| 151 | + e_ops::Union{Nothing, AbstractVector}=nothing, |
| 152 | + kwargs..., |
| 153 | + ) |
| 154 | +
|
| 155 | +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. |
| 156 | +
|
| 157 | +## Arguments |
| 158 | +
|
| 159 | +- `H`: The system Hamiltonian. Must be an [`Operator`](@ref) |
| 160 | +- `ψ0`: Initial state of the system $|\psi(0)\rangle$. It can be either a [`Ket`](@ref), [`Operator`](@ref) or [`OperatorKet`](@ref). |
| 161 | +- `tlist`: List of times at which to save either the state or the expectation values of the system. |
| 162 | +- `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 |
| 163 | +- `c_ops`: List of collapse operators corresponding to Lindblad dissipators |
| 164 | +- `sec_cutoff`: Cutoff for secular approximation. Use `-1` if secular approximation is not used when evaluating bath-coupling terms. |
| 165 | +- `e_ops`: List of operators for which to calculate expectation values. It can be either a `Vector` or a `Tuple`. |
| 166 | +- `kwargs`: Keyword arguments for [`mesolve`](@ref). |
| 167 | +
|
| 168 | +## Notes |
| 169 | +
|
| 170 | +- This function will automatically generate the [`bloch_redfield_tensor`](@ref) and solve the time evolution with [`mesolve`](@ref). |
| 171 | +
|
| 172 | +# Returns |
| 173 | +
|
| 174 | +- `sol::TimeEvolutionSol`: The solution of the time evolution. See also [`TimeEvolutionSol`](@ref) |
| 175 | +""" |
| 176 | +function brmesolve( |
| 177 | + H::QuantumObject{Operator}, |
| 178 | + ψ0::QuantumObject, |
| 179 | + tlist::AbstractVector, |
| 180 | + a_ops::Union{Nothing,AbstractVector,Tuple}, |
| 181 | + c_ops::Union{Nothing,AbstractVector,Tuple} = nothing; |
| 182 | + sec_cutoff::Real = 0.1, |
| 183 | + e_ops::Union{Nothing,AbstractVector} = nothing, |
| 184 | + kwargs..., |
| 185 | +) |
| 186 | + R = bloch_redfield_tensor(H, a_ops, c_ops; sec_cutoff = sec_cutoff, fock_basis = Val(true)) |
| 187 | + |
| 188 | + return mesolve(R, ψ0, tlist, nothing; e_ops = e_ops, kwargs...) |
| 189 | +end |
| 190 | + |
| 191 | +function _check_br_spectra(f::Function) |
| 192 | + meths = methods(f, [Real]) |
| 193 | + length(meths.ms) == 0 && |
| 194 | + throw(ArgumentError("The following function must accept one argument: `$(meths.mt.name)(ω)` with ω<:Real")) |
| 195 | + return nothing |
| 196 | +end |
0 commit comments