From 51684ab99544e57b1ff8404e5dffc84f2e8acc8b Mon Sep 17 00:00:00 2001 From: Yi-Te Huang <44385685+ytdHuang@users.noreply.github.com> Date: Fri, 4 Oct 2024 22:17:16 +0800 Subject: [PATCH] Introduce `convert_unit` (#255) * introduce `convert_unit` * add tests for utility functions * fix value of physical constants --- docs/src/api.md | 1 + src/utilities.jl | 46 ++++++++++++++++++++++++++++++++++++- test/core-test/utilities.jl | 45 ++++++++++++++++++++++++++++++++++++ test/runtests.jl | 1 + 4 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 test/core-test/utilities.jl diff --git a/docs/src/api.md b/docs/src/api.md index 30c367bb..4fa4131f 100644 --- a/docs/src/api.md +++ b/docs/src/api.md @@ -239,6 +239,7 @@ QuantumToolbox.versioninfo QuantumToolbox.about gaussian n_thermal +convert_unit row_major_reshape meshgrid _calculate_expectation! diff --git a/src/utilities.jl b/src/utilities.jl index d81b5f8d..74af168b 100644 --- a/src/utilities.jl +++ b/src/utilities.jl @@ -3,7 +3,7 @@ Utilities: internal (or external) functions which will be used throughout the entire package =# -export gaussian, n_thermal +export gaussian, n_thermal, convert_unit export row_major_reshape, meshgrid @doc raw""" @@ -48,6 +48,50 @@ function n_thermal(ω::T1, ω_th::T2) where {T1<:Real,T2<:Real} return _FType(promote_type(T1, T2))(n) end +# some fundamental physical constants and common energy units +const _e = 1.602176565e-19 # elementary charge (C) +const _kB = 1.3806488e-23 # Boltzmann constant (J/K) +const _h = 6.62607015e-34 # Planck constant (J⋅s) +const _energy_units::Dict{Symbol,Float64} = Dict( + # the values below are all in the unit of Joule + :J => 1.0, + :eV => _e, + :meV => 1e-3 * _e, + :GHz => 1e9 * _h, + :mK => 1e-3 * _kB, +) + +@doc raw""" + convert_unit(value::Real, unit1::Symbol, unit2::Symbol) + +Convert the energy `value` from `unit1` to `unit2`. + +Note that `unit1` and `unit2` can be either the following `Symbol`: +- `:J`: Joule +- `:eV`: electron volt. +- `:meV`: milli-electron volt. +- `:GHz`: Giga-Hertz multiplied by Planck constant ``h``. +- `:mK`: milli-Kelvin multiplied by Boltzmann constant ``k_{\textrm{B}}``. + +# Examples + +``` +julia> convert_unit(1, :eV, :J) +1.602176565e-19 + +julia> convert_unit(1, :GHz, :J) +6.62607015e-25 + +julia> convert_unit(1, :meV, :mK) +11604.51930280894 +``` +""" +function convert_unit(value::T, unit1::Symbol, unit2::Symbol) where {T<:Real} + !haskey(_energy_units, unit1) && throw(ArgumentError("Invalid unit :$(unit1)")) + !haskey(_energy_units, unit2) && throw(ArgumentError("Invalid unit :$(unit2)")) + return _FType(T)(value * (_energy_units[unit1] / _energy_units[unit2])) +end + _get_dense_similar(A::AbstractArray, args...) = similar(A, args...) _get_dense_similar(A::AbstractSparseMatrix, args...) = similar(nonzeros(A), args...) diff --git a/test/core-test/utilities.jl b/test/core-test/utilities.jl new file mode 100644 index 00000000..5d269d69 --- /dev/null +++ b/test/core-test/utilities.jl @@ -0,0 +1,45 @@ +@testset "Utilities" verbose = true begin + @testset "n_thermal" begin + ω1 = rand(Float64) + ω2 = rand(Float64) + @test n_thermal(0, ω2) == 0.0 + @test n_thermal(ω1, 0) == 0.0 + @test n_thermal(ω1, -ω2) == 0.0 + @test n_thermal(ω1, ω2) == 1 / (exp(ω1 / ω2) - 1) + @test typeof(n_thermal(Int32(2), Int32(3))) == Float32 + @test typeof(n_thermal(Float32(2), Float32(3))) == Float32 + @test typeof(n_thermal(Int64(2), Int32(3))) == Float64 + @test typeof(n_thermal(Int32(2), Int64(3))) == Float64 + @test typeof(n_thermal(Float64(2), Float32(3))) == Float64 + @test typeof(n_thermal(Float32(2), Float64(3))) == Float64 + end + + @testset "convert unit" begin + V = 100 * rand(Float64) + _unit_list = [:J, :eV, :meV, :GHz, :mK] + for origin in _unit_list + for middle in _unit_list + for target in _unit_list + V_middle = convert_unit(V, origin, middle) + V_target = convert_unit(V_middle, middle, target) + V_origin = convert_unit(V_target, target, origin) + @test V ≈ V_origin + end + end + end + @test_throws ArgumentError convert_unit(V, :bad_unit, :J) + @test_throws ArgumentError convert_unit(V, :J, :bad_unit) + end + + @testset "Type Inference" begin + v1 = rand(Float64) + @inferred n_thermal(v1, Int32(123)) + + _unit_list = [:J, :eV, :meV, :GHz, :mK] + for u1 in _unit_list + for u2 in _unit_list + @inferred convert_unit(v1, u1, u2) + end + end + end +end diff --git a/test/runtests.jl b/test/runtests.jl index 70c361cd..95709e3a 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -23,6 +23,7 @@ core_tests = [ "states_and_operators.jl", "steady_state.jl", "time_evolution.jl", + "utilities.jl", "wigner.jl", ]