Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 13 additions & 19 deletions src/transforms/redshift.jl
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,18 @@ function _doppler_factor(v; relativistic)
end

# Resolve the (1 + z) stretch factor to the scalar actually multiplied onto a spectral axis of element type `S`.
_axis_factor(::Type{<:Real}, factor) = factor # Unitless: assume wavelength
_axis_factor(::Type{<:Unitful.Length}, factor) = factor # Wavelength: stretches
_axis_factor(::Type{<:Unitful.Energy}, factor) = inv(factor) # Energy: compresses
_axis_factor(::Type{S}, factor) where {S <: Unitful.Quantity} =
_spectral_axis_factor(::Type{<:Real}, factor) = factor # Unitless: assume wavelength
_spectral_axis_factor(::Type{<:Unitful.Length}, factor) = factor # Wavelength: stretches
_spectral_axis_factor(::Type{<:Unitful.Energy}, factor) = inv(factor) # Energy: compresses
_spectral_axis_factor(::Type{S}, factor) where {S <: Unitful.Quantity} =
throw(ArgumentError("cannot shift a spectral axis with dimension $(dimension(S)); expected a wavelength or energy"))
_axis_factor(spec::AbstractSpectrum, factor) = _axis_factor(eltype(spectral_axis(spec)), factor)

# Return a copy of `spec` whose spectral axis is scaled by `factor`. Rebuilding
# through the constructor (rather than reassigning the field) lets the element
# type promote, e.g., an integer axis becomes floating point, and re-runs the
# `Spectrum` invariant checks. `R` and the type assertions recover the inference
# that is otherwise lost through the `getproperty` overload.
function _scale_spectral_axis(spec::Spectrum{S, F, M, N}, factor) where {S, F, M, N}
f = _axis_factor(S, factor)
R = typeof(oneunit(S) * f)
axis = (spectral_axis(spec) .* f)::AbstractArray{R, M}
flux = copy(flux_axis(spec))::AbstractArray{F, N}
return Spectrum(axis, flux, deepcopy(meta(spec)))
_spectral_axis_factor(spec::AbstractSpectrum, factor) = _spectral_axis_factor(eltype(spectral_axis(spec)), factor)

# Rebuilding through the constructor lets the element type promote and re-runs the invariant checks.
function _scale_spectral_axis(spec::Spectrum{S}, factor) where {S}
spectral_ax = spectral_axis(spec) .* _spectral_axis_factor(S, factor)
flux_ax = copy(flux_axis(spec))
return Spectrum(spectral_ax, flux_ax, deepcopy(meta(spec)))
end

"""
Expand All @@ -41,7 +35,7 @@ Reassigns the spectral axis, so its element and array type cannot change.
Use [`redshift`](@ref) for spectra with an integer spectral axis.
"""
function redshift!(spec::AbstractSpectrum, z::Real)
spec.spectral_axis = spectral_axis(spec) .* _axis_factor(spec, 1 + z)
spec.spectral_axis = spectral_axis(spec) .* _spectral_axis_factor(spec, 1 + z)
return spec
end

Expand Down Expand Up @@ -92,7 +86,7 @@ Reassigns the spectral axis, so its element and array type cannot change. Use [`
for spectra with an integer spectral axis.
"""
function doppler_shift!(spec::AbstractSpectrum, v; relativistic = false)
spec.spectral_axis = spectral_axis(spec) .* _axis_factor(spec, _doppler_factor(v; relativistic))
spec.spectral_axis = spectral_axis(spec) .* _spectral_axis_factor(spec, _doppler_factor(v; relativistic))
return spec
end

Expand Down
7 changes: 7 additions & 0 deletions test/transforms/redshift.jl
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,13 @@ end
spec = spectrum(axis, ones(10) * u"erg/s/cm^2/angstrom")
@test spectral_axis(redshift(spec, 0.5)) ≈ axis .* 1.5
end

@testset "Unsupported axis dimension rejected" begin
# Constructed directly, bypassing the dimension guard in `spectrum`
axis = collect(range(1.0, 5.0, length = 10)) * u"s"
spec = SpectrumBase.Spectrum(axis, ones(10) * u"erg/s/cm^2/angstrom", Dict{Symbol, Any}())
@test_throws ArgumentError redshift(spec, 0.5)
end
end

@testset "doppler_shift" begin
Expand Down
Loading