-
Notifications
You must be signed in to change notification settings - Fork 31
Bloch Redfield master equation implementation #473
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 19 commits
Commits
Show all changes
22 commits
Select commit
Hold shift + click to select a range
829cb4f
first commit
TendonFFF 596aa4c
function `brterm`
TendonFFF 60ca0b7
add `bloch_redfield_tensor`
TendonFFF de2cb6d
delete copy
TendonFFF dc5c84e
remove brcrossterm and unneccesary import
TendonFFF 97f5bd0
add tests
TendonFFF c12ba94
formatting
TendonFFF b676b14
change file name and location
TendonFFF 141b778
fix typo
TendonFFF 5977dcf
Merge branch 'main' into dev/brme
TendonFFF 7616a2a
use `@testitem` in test
TendonFFF 33878e8
add to api
TendonFFF d05f5c5
formatting test
TendonFFF 98c590c
export functions
TendonFFF 7432021
fix bug for `Id`
TendonFFF db466f0
add test for `brmesolve`
TendonFFF 65ef450
improve test for `brmesolve`
TendonFFF 72a31cd
fix `brmesolve` test
TendonFFF 17e0936
formatting
TendonFFF 38beb4a
implement comments by @ytdHuang
TendonFFF 1ca7f34
change log
TendonFFF cc0947d
Merge branch 'main' into dev/brme
TendonFFF File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,202 @@ | ||
| export bloch_redfield_tensor, brterm, brmesolve | ||
|
|
||
| @doc raw""" | ||
| bloch_redfield_tensor( | ||
| H::QuantumObject{Operator}, | ||
| a_ops::Union{AbstractVector, Tuple}, | ||
| c_ops::Union{AbstractVector, Tuple, Nothing}=nothing; | ||
| sec_cutoff::Real=0.1, | ||
| fock_basis::Union{Val,Bool}=Val(false) | ||
| ) | ||
| 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. | ||
| ## Arguments | ||
| - `H`: The system Hamiltonian. Must be an [`Operator`](@ref) | ||
| - `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 | ||
| - `c_ops`: List of collapse operators corresponding to Lindblad dissipators | ||
| - `sec_cutoff`: Cutoff for secular approximation. Use `-1` if secular approximation is not used when evaluating bath-coupling terms. | ||
| - `fock_basis`: Whether to return the tensor in the input (fock) basis or the diagonalized (eigen) basis. | ||
| ## Return | ||
| The return depends on `fock_basis`. | ||
| - `fock_basis=Val(true)`: return the Bloch-Redfield tensor (in the fock basis) only. | ||
| - `fock_basis=Val(false)`: return the Bloch-Redfield tensor (in the eigen basis) along with the transformation matrix from eigen to fock basis. | ||
| """ | ||
| function bloch_redfield_tensor( | ||
| H::QuantumObject{Operator}, | ||
| a_ops::Union{AbstractVector,Tuple}, | ||
| c_ops::Union{AbstractVector,Tuple,Nothing} = nothing; | ||
| sec_cutoff::Real = 0.1, | ||
| fock_basis::Union{Val,Bool} = Val(false), | ||
| ) | ||
| rst = eigenstates(H) | ||
| U = QuantumObject(rst.vectors, Operator(), H.dimensions) | ||
| sec_cutoff = float(sec_cutoff) | ||
|
|
||
| # in fock basis | ||
| R0 = liouvillian(H, c_ops) | ||
|
|
||
| # set fock_basis=Val(false) and change basis together at the end | ||
| R1 = 0 | ||
| if !isempty(a_ops) | ||
| R1 += mapreduce(x -> _brterm(rst, x[1], x[2], sec_cutoff, Val(false)), +, a_ops) | ||
|
|
||
| # do (a_op, spectra) | ||
| # _brterm(rst, a_op, spectra, sec_cutoff, Val(false)) | ||
| # end | ||
ytdHuang marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| end | ||
|
|
||
| SU = sprepost(U, U') # transformation matrix from eigen basis back to fock basis | ||
| if getVal(fock_basis) | ||
| return R0 + SU * R1 * SU' | ||
| else | ||
| return SU' * R0 * SU + R1, U | ||
| end | ||
| end | ||
|
|
||
| @doc raw""" | ||
| brterm( | ||
| H::QuantumObject{Operator}, | ||
| a_op::QuantumObject{Operator}, | ||
| spectra::Function; | ||
| sec_cutoff::Real=0.1, | ||
| fock_basis::Union{Bool, Val}=Val(false) | ||
| ) | ||
| Calculates the contribution of one coupling operator to the Bloch-Redfield tensor. | ||
| ## Argument | ||
| - `H`: The system Hamiltonian. Must be an [`Operator`](@ref) | ||
| - `a_op`: The operator coupling to the environment. Must be hermitian. | ||
| - `spectra`: The corresponding environment spectra as a `Function` of transition energy. | ||
| - `sec_cutoff`: Cutoff for secular approximation. Use `-1` if secular approximation is not used when evaluating bath-coupling terms. | ||
| - `fock_basis`: Whether to return the tensor in the input (fock) basis or the diagonalized (eigen) basis. | ||
| ## Return | ||
| The return depends on `fock_basis`. | ||
| - `fock_basis=Val(true)`: return the Bloch-Redfield term (in the fock basis) only. | ||
| - `fock_basis=Val(false)`: return the Bloch-Redfield term (in the eigen basis) along with the transformation matrix from eigen to fock basis. | ||
| """ | ||
| function brterm( | ||
| H::QuantumObject{Operator}, | ||
| a_op::QuantumObject{Operator}, | ||
| spectra::Function; | ||
| sec_cutoff::Real = 0.1, | ||
| fock_basis::Union{Bool,Val} = Val(false), | ||
| ) | ||
| rst = eigenstates(H) | ||
| term = _brterm(rst, a_op, spectra, sec_cutoff, makeVal(fock_basis)) | ||
| if getVal(fock_basis) | ||
| return term | ||
| else | ||
| return term, Qobj(rst.vectors, Operator(), rst.dimensions) | ||
| end | ||
| end | ||
|
|
||
| function _brterm( | ||
| rst::EigsolveResult, | ||
| a_op::T, | ||
| spectra::F, | ||
| sec_cutoff::Real, | ||
| fock_basis::Union{Val{true},Val{false}}, | ||
| ) where {T<:QuantumObject{Operator},F<:Function} | ||
| _check_br_spectra(spectra) | ||
|
|
||
| U, N = rst.vectors, prod(rst.dimensions) | ||
| Id = I(N) | ||
ytdHuang marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| skew = @. rst.values - rst.values' |> real | ||
| spectrum = spectra.(skew) | ||
|
|
||
| A_mat = U' * a_op.data * U | ||
|
|
||
| ac_term = (A_mat .* spectrum) * A_mat | ||
| bd_term = A_mat * (A_mat .* trans(spectrum)) | ||
|
|
||
| if sec_cutoff != -1 | ||
| m_cut = similar(skew) | ||
| map!(x -> abs(x) < sec_cutoff, m_cut, skew) | ||
| ac_term .*= m_cut | ||
| bd_term .*= m_cut | ||
|
|
||
| vec_skew = vec(skew) | ||
| M_cut = @. abs(vec_skew - vec_skew') < sec_cutoff | ||
| end | ||
|
|
||
| out = | ||
| 0.5 * ( | ||
| + _sprepost(A_mat .* trans(spectrum), A_mat) + _sprepost(A_mat, A_mat .* spectrum) - _spost(ac_term, Id) - | ||
| _spre(bd_term, Id) | ||
| ) | ||
|
|
||
| (sec_cutoff != -1) && (out .*= M_cut) | ||
|
|
||
| if getVal(fock_basis) | ||
| SU = _sprepost(U, U') | ||
| return QuantumObject(SU * out * SU', SuperOperator(), rst.dimensions) | ||
| else | ||
| return QuantumObject(out, SuperOperator(), rst.dimensions) | ||
| end | ||
| end | ||
|
|
||
| @doc raw""" | ||
| brmesolve( | ||
| H::QuantumObject{Operator}, | ||
| ψ0::QuantumObject, | ||
| tlist::AbstractVector, | ||
| a_ops::Union{Nothing, AbstractVector, Tuple}, | ||
| c_ops::Union{Nothing, AbstractVector, Tuple}=nothing; | ||
| sec_cutoff::Real=0.1, | ||
| e_ops::Union{Nothing, AbstractVector}=nothing, | ||
| kwargs..., | ||
| ) | ||
| 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. | ||
| ## Arguments | ||
| - `H`: The system Hamiltonian. Must be an [`Operator`](@ref) | ||
| - `ψ0`: Initial state of the system $|\psi(0)\rangle$. It can be either a [`Ket`](@ref), [`Operator`](@ref) or [`OperatorKet`](@ref). | ||
| - `tlist`: List of times at which to save either the state or the expectation values of the system. | ||
| - `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 | ||
| - `c_ops`: List of collapse operators corresponding to Lindblad dissipators | ||
| - `sec_cutoff`: Cutoff for secular approximation. Use `-1` if secular approximation is not used when evaluating bath-coupling terms. | ||
| - `e_ops`: List of operators for which to calculate expectation values. It can be either a `Vector` or a `Tuple`. | ||
| - `kwargs`: Keyword arguments for [`mesolve`](@ref). | ||
| ## Notes | ||
| - This function will automatically generate the [`bloch_redfield_tensor`](@ref) and solve the time evolution with [`mesolve`](@ref). | ||
| # Returns | ||
| - `sol::TimeEvolutionSol`: The solution of the time evolution. See also [`TimeEvolutionSol`](@ref) | ||
| """ | ||
| function brmesolve( | ||
| H::QuantumObject{Operator}, | ||
| ψ0::QuantumObject, | ||
| tlist::AbstractVector, | ||
| a_ops::Union{Nothing,AbstractVector,Tuple}, | ||
| c_ops::Union{Nothing,AbstractVector,Tuple} = nothing; | ||
| sec_cutoff::Real = 0.1, | ||
| e_ops::Union{Nothing,AbstractVector} = nothing, | ||
| kwargs..., | ||
| ) | ||
| R = bloch_redfield_tensor(H, a_ops, c_ops; sec_cutoff = sec_cutoff, fock_basis = Val(true)) | ||
|
|
||
| return mesolve(R, ψ0, tlist, nothing; e_ops = e_ops, kwargs...) | ||
| end | ||
|
|
||
| function _check_br_spectra(f::Function) | ||
| meths = methods(f, [Real]) | ||
| length(meths.ms) == 0 && | ||
| throw(ArgumentError("The following function must accept one argument: `$(meths.mt.name)(ω)` with ω<:Real")) | ||
| return nothing | ||
| end | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,115 @@ | ||
| @testitem "Bloch-Redfield tensor sec_cutoff" begin | ||
| N = 5 | ||
| H = num(N) | ||
| a = destroy(N) | ||
| A_op = a+a' | ||
| spectra(x) = (x>0) * 0.5 | ||
| for sec_cutoff in [0, 0.1, 1, 3, -1] | ||
| R = bloch_redfield_tensor(H, [(A_op, spectra)], [a^2], sec_cutoff = sec_cutoff, fock_basis = true) | ||
| R_eig, evecs = bloch_redfield_tensor(H, [(A_op, spectra)], [a^2], sec_cutoff = sec_cutoff, fock_basis = false) | ||
| @test isa(R, QuantumObject) | ||
| @test isa(R_eig, QuantumObject) | ||
| @test isa(evecs, QuantumObject) | ||
|
|
||
| state = rand_dm(N) |> mat2vec | ||
| fock_computed = R * state | ||
| eig_computed = (sprepost(evecs, evecs') * R_eig * sprepost(evecs', evecs)) * state | ||
| @test isapprox(fock_computed, eig_computed, atol = 1e-15) | ||
| end | ||
| end | ||
|
|
||
| @testitem "Compare brterm and Lindblad" begin | ||
| N = 5 | ||
| H = num(N) | ||
| a = destroy(N) + destroy(N)^2/2 | ||
| A_op = a+a' | ||
| spectra(x) = x>0 | ||
|
|
||
| # this test applies for limited cutoff | ||
| lindblad = lindblad_dissipator(a) | ||
| computation = brterm(H, A_op, spectra, sec_cutoff = 1.5, fock_basis = true) | ||
| @test isapprox(lindblad, computation, atol = 1e-15) | ||
| end | ||
|
|
||
| @testitem "brterm basis" begin | ||
| N = 5 | ||
| H = num(N) | ||
| a = destroy(N) + destroy(N)^2/2 | ||
| A_op = a+a' | ||
| spectra(x) = x>0 | ||
| for sec_cutoff in [0, 0.1, 1, 3, -1] | ||
| R = brterm(H, A_op, spectra, sec_cutoff = sec_cutoff, fock_basis = true) | ||
| R_eig, evecs = brterm(H, A_op, spectra, sec_cutoff = sec_cutoff, fock_basis = false) | ||
| @test isa(R, QuantumObject) | ||
| @test isa(R_eig, QuantumObject) | ||
| @test isa(evecs, QuantumObject) | ||
|
|
||
| state = rand_dm(N) |> mat2vec | ||
| fock_computed = R * state | ||
| eig_computed = (sprepost(evecs, evecs') * R_eig * sprepost(evecs', evecs)) * state | ||
| @test isapprox(fock_computed, eig_computed, atol = 1e-15) | ||
| end; | ||
| end | ||
|
|
||
| @testitem "brterm sprectra function" begin | ||
| f(x) = exp(x)/10 | ||
| function g(x) | ||
| nbar = n_thermal(abs(x), 1) | ||
| if x > 0 | ||
| return nbar | ||
| elseif x < 0 | ||
| return 1 + nbar | ||
| else | ||
| return 0.0 | ||
| end | ||
| end | ||
|
|
||
| spectra_list = [ | ||
| x -> (x>0), # positive frequency filter | ||
| x -> one(x), # no filter | ||
| f, # smooth filter | ||
| g, # thermal field | ||
| ] | ||
|
|
||
| N = 5 | ||
| H = num(N) | ||
| a = destroy(N) + destroy(N)^2/2 | ||
| A_op = a+a' | ||
| for spectra in spectra_list | ||
| R = brterm(H, A_op, spectra, sec_cutoff = 0.1, fock_basis = true) | ||
| R_eig, evecs = brterm(H, A_op, spectra, sec_cutoff = 0.1, fock_basis = false) | ||
| @test isa(R, QuantumObject) | ||
| @test isa(R_eig, QuantumObject) | ||
| @test isa(evecs, QuantumObject) | ||
|
|
||
| state = rand_dm(N) |> mat2vec | ||
| fock_computed = R * state | ||
| eig_computed = (sprepost(evecs, evecs') * R_eig * sprepost(evecs', evecs)) * state | ||
| @test isapprox(fock_computed, eig_computed, atol = 1e-15) | ||
| end | ||
| end | ||
|
|
||
| @testitem "simple qubit system" begin | ||
| pauli_vectors = [sigmax(), sigmay(), sigmaz()] | ||
| γ = 0.25 | ||
| spectra(x) = γ * (x>=0) | ||
| _m_c_op = √γ * sigmam() | ||
| _z_c_op = √γ * sigmaz() | ||
| _x_a_op = (sigmax(), spectra) | ||
|
|
||
| arg_sets = [[[_m_c_op], [], [_x_a_op]], [[_m_c_op], [_m_c_op], []], [[_m_c_op, _z_c_op], [_z_c_op], [_x_a_op]]] | ||
|
|
||
| δ = 0 | ||
| ϵ = 0.5 * 2π | ||
| e_ops = pauli_vectors | ||
| H = δ * 0.5 * sigmax() + ϵ * 0.5 * sigmaz() | ||
| ψ0 = unit(2basis(2, 0) + basis(2, 1)) | ||
| times = LinRange(0, 10, 100) | ||
|
|
||
| for (me_c_ops, brme_c_ops, brme_a_ops) in arg_sets | ||
| me = mesolve(H, ψ0, times, me_c_ops, e_ops = e_ops, progress_bar = Val(false)) | ||
| brme = brmesolve(H, ψ0, times, brme_a_ops, brme_c_ops, e_ops = e_ops, progress_bar = Val(false)) | ||
|
|
||
| @test all(me.expect .== brme.expect) | ||
| end | ||
| end; |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.