-
Notifications
You must be signed in to change notification settings - Fork 29
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
Added a method to read an image into a pre-allocated array #122
Changes from 3 commits
0d688e9
a4ad156
f2fbf1e
fe77cb4
82f7f1d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,6 +18,7 @@ import Base: getindex, | |
length, | ||
show, | ||
read, | ||
read!, | ||
write, | ||
close, | ||
ndims, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -87,6 +87,42 @@ function read(hdu::ImageHDU) | |
data | ||
end | ||
|
||
""" | ||
read!(hdu::ImageHDU, output::AbstractArray) | ||
read!(hdu::ImageHDU, output::AbstractArray, range...) | ||
|
||
Read the data array or a subset thereof from disk, and save it in the | ||
preallocated output array. | ||
The first form reads the entire data array. | ||
The second form reads a slice of the array given by the specified ranges or integers. | ||
The output array needs to have the same shape as the data range to be read in. | ||
""" | ||
function read!(hdu::ImageHDU, output::AbstractArray{T,N}) where {T,N} | ||
fits_assert_open(hdu.fitsfile) | ||
fits_movabs_hdu(hdu.fitsfile, hdu.ext) | ||
sz = fits_get_img_size(hdu.fitsfile) | ||
bitpix = fits_get_img_equivtype(hdu.fitsfile) | ||
|
||
if TYPE_FROM_BITPIX[bitpix] != T | ||
throw(TypeError(:read!,"",TYPE_FROM_BITPIX[bitpix],T)) | ||
end | ||
|
||
if ndims(hdu) != N | ||
throw(DimensionMismatch("array dimensions do not match the data. "* | ||
"Data has $(ndims(hdu)) dimensions whereas the output array has $N dimensions.")) | ||
end | ||
|
||
# Maybe this can be a ShapeMismatch when there's a decision on #16717 | ||
if Tuple(sz) != size(output) | ||
throw(DimensionMismatch("size of the array does not "* | ||
"match the data. Data has a size of $(Tuple(sz)) whereas the output array "* | ||
"has a size of $(size(output))")) | ||
end | ||
|
||
fits_read_pix(hdu.fitsfile, output) | ||
output | ||
end | ||
|
||
# _checkbounds methods copied from Julia v0.4 Base. | ||
_checkbounds(sz, i::Integer) = 1 <= i <= sz | ||
_checkbounds(sz, i::Colon) = true | ||
|
@@ -144,11 +180,58 @@ function read_internal(hdu::ImageHDU, I::Union{AbstractRange{Int}, Integer, Colo | |
data | ||
end | ||
|
||
function read_internal!(hdu::ImageHDU, output::AbstractArray{T,N}, | ||
I::Union{AbstractRange{Int}, Integer, Colon}...) where {T,N} | ||
|
||
# check that the output array has the right type | ||
bitpix = fits_get_img_equivtype(hdu.fitsfile) | ||
if TYPE_FROM_BITPIX[bitpix] != T | ||
throw(TypeError(:read!,"",TYPE_FROM_BITPIX[bitpix],T)) | ||
end | ||
|
||
fits_assert_open(hdu.fitsfile) | ||
fits_movabs_hdu(hdu.fitsfile, hdu.ext) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These two lines should come first in the function, so that fits_get_img_equivtype operates on the intended extension There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have fixed this in the latest commit. |
||
sz = fits_get_img_size(hdu.fitsfile) | ||
|
||
# check number of indices and bounds. Note that number of indices and | ||
# array dimension must match, unlike in Arrays. Array-like behavior could | ||
# be supported in the future with care taken in constructing first, last, | ||
if length(I) != length(sz) | ||
throw(DimensionMismatch("number of indices must match dimensions")) | ||
end | ||
|
||
for i=1:length(sz) | ||
_checkbounds(sz[i], I[i]) || throw(BoundsError()) | ||
end | ||
|
||
ninds = _index_shape(sz, I...) | ||
if length(ninds) != N | ||
throw(DimensionMismatch("number of indices must match the "* | ||
"number of dimensions of the output array")) | ||
end | ||
|
||
if size(output) != ninds | ||
throw(DimensionMismatch("size of the data slice must match that of the output array. "* | ||
"Data has a size of $ninds whereas the output array has a size of $(size(output))")) | ||
end | ||
|
||
# construct first, last and step vectors | ||
firsts = Clong[_first(idx) for idx in I] | ||
lasts = Clong[_last(sz[i], I[i]) for i=1:length(sz)] | ||
steps = Clong[_step(idx) for idx in I] | ||
|
||
fits_read_subset(hdu.fitsfile, firsts, lasts, steps, output) | ||
output | ||
end | ||
|
||
# general method and version that returns a single value rather than 0-d array | ||
read(hdu::ImageHDU, I::Union{AbstractRange{Int}, Int, Colon}...) = | ||
read_internal(hdu, I...) | ||
read(hdu::ImageHDU, I::Int...) = read_internal(hdu, I...)[1] | ||
|
||
read!(hdu::ImageHDU, output::AbstractArray, I::Union{AbstractRange{Int}, Int, Colon}...) = | ||
read_internal!(hdu, output, I...) | ||
read!(hdu::ImageHDU, output::AbstractArray, I::Int...) = read_internal!(hdu, output, I...)[1] | ||
|
||
""" | ||
write(f::FITS, data::Array; header=nothing, name=nothing, ver=nothing) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -71,6 +71,72 @@ using Random # for `randstring` | |
rm(fname1, force=true) | ||
rm(fname2, force=true) | ||
end | ||
|
||
@testset "non-allocating read" begin | ||
fname1 = tempname() * ".fits" | ||
try | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note that instead of using FITS(fname, "w") do f
# ...
end which will automatically close it at the end. You can find some examples in this file. The There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you still need this try...finally block to delete the temp file, no? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have updated the tests to use this method There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @kbarbary there is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||
f1 = FITS(fname1, "w") | ||
indata = reshape(Float32[1:400;], 20, 20) | ||
write(f1, indata) | ||
close(f1) | ||
f1 = FITS(fname1, "r") | ||
a = read(f1[1]) | ||
|
||
# Read the entire array | ||
b = zeros(eltype(indata),size(indata)) | ||
read!(f1[1],b) | ||
@test a == b | ||
read!(f1[1],b,:,:) | ||
@test a == b | ||
|
||
# Read a 2D slice | ||
b = zeros(eltype(indata),2,2) | ||
read!(f1[1],b,1:2,1:2) | ||
@test a[1:2,1:2] == b | ||
|
||
# Read an entire 1D slice | ||
b = zeros(eltype(indata),size(indata,1)) | ||
read!(f1[1],b,:,1) | ||
@test a[:,1] == b | ||
|
||
b = zeros(eltype(indata),size(indata,2)) | ||
read!(f1[1],b,1,:) | ||
@test a[1,:] == b | ||
|
||
# Read a part of a 1D slice | ||
b = zeros(eltype(indata),1) | ||
read!(f1[1],b,1:1,1) | ||
@test a[1,1] == b[1] | ||
read!(f1[1],b,1,1:1) | ||
@test a[1,1] == b[1] | ||
|
||
# Read a single element into a 0-dim array | ||
b = zeros(eltype(indata)) | ||
read!(f1[1],b,1,1) | ||
@test a[1,1] == first(b) | ||
|
||
# Test for errors | ||
b = zeros(Float64) | ||
# Type is checked before dimensions | ||
@test_throws TypeError read!(f1[1],b,1,1) | ||
@test_throws TypeError read!(f1[1],b) | ||
|
||
b = zeros(eltype(indata)) | ||
@test_throws DimensionMismatch read!(f1[1],b,1:10,1) | ||
@test_throws DimensionMismatch read!(f1[1],b,1:10,1:10) | ||
@test_throws DimensionMismatch read!(f1[1],b) | ||
@test_throws DimensionMismatch read!(f1[1],b,:,1) | ||
@test_throws DimensionMismatch read!(f1[1],b,1,:) | ||
@test_throws DimensionMismatch read!(f1[1],b,:,:) | ||
|
||
b = zeros(eltype(indata),1) | ||
@test_throws DimensionMismatch read!(f1[1],b,1,1) | ||
|
||
close(f1) | ||
finally | ||
rm(fname1, force=true) | ||
end | ||
end | ||
end | ||
|
||
@testset "Write data to an existing image HDU" begin | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this refers to JuliaLang/julia#16717, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes that's what I had in mind