Skip to content

yuasatakayuki/RubyFits

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

87 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

RubyFits

A Ruby FITS I/O library based on C++ sfitsio.

RubyFits is an easy-to-use Ruby library that can be used to manipulate files in the FITS format, the standard file format for astronomy and astrophysics.

The library uses the C++ sfitsio library by Chisato Yamauchi via the SWIG interface generator.

Install

To install this library, do the following:

  1. RubyFits needs http://www.ir.isas.jaxa.jp/~cyamauch/sli/index.html|sllib and http://www.ir.isas.jaxa.jp/~cyamauch/sli/index.html|sfitsio to be installed. These libraries can be installed via Homebrew, and execute the following if you are missing these nice libraries.
    brew tap yuasatakayuki/hxisgd
    brew install sfitsio
    
  2. Clone (download) from github.
    git clone https://github.com/yuasatakayuki/RubyFits.git
    
  3. Build with cmake.
    cd RubyFits/swig
    mkdir build
    cd build
    cmake ..
    make install
    
    Compiled library will be installed to $HOME/lib/ruby. If you do not like this, modify install prefix with -DCMAKE_INSTALL_PREFIX like:
    cmake .. -DCMAKE_INSTALL_PREFIX=/usr/local
    
  4. In the ruby scritps, you can import RubyFits by doing like:
    require "RubyFits"
    include Fits
    
  5. Define RUBYLIB to direct "$HOME/lib/ruby" in your .zshrc for example.
    export RUBYLIB=$HOME/lib/ruby
    

Contact

  • Takayuki Yuasa
    • 2014- RIKEN The Institute of Physical and Chemical Research
    • 2011-2014 Japan Aerospace Exploration Agency (JAXA)
    • takayuki.yuasa _atmark_ riken.jp

API Reference

Usage

In the example/ folder, there are some scripts showing usages of RubyFits. "samplteTable.fits" can be used as a sample FITS file.

  • readTable.rb well describes how to read TableHDU in a FITS file.

Open/Save

See openSave.rb.

require "RubyFits"
include Fits

f=FitsFile.new("sampleTable.fits")
puts f
puts f[0].headerKeyValueComment(1)

You can open a file after constructing an empty instance first.

f=FitsFile.new
f.open("sampleTable.fits")

Save.

#save to file
f.saveAs("openSave.fits")

You can check the saved FITS file with fv for example (HEASOFT should be installed):

fv openSave.fits

FitsFile::saveAs() has some aliases:

  • writeToFile
  • saveToFile
  • writeToFile
  • write
  • save
  • writeTo
  • saveTo

Header access

See openSave.rb.

A FitsFile instance contains one or more HDU (header data unit, or sometimes called 'extension'). They can be accessed via one of the following accessors:

f=FitsFile.new("sampleTable.fits")
f.hdu(1)          # by index
f[1]              # by index
f.hdu("SPECTRUM") # by name

An HDU contains Header and Data (table or image). Key-value records in a header can be accesses as follows:

#dump the 1-st and 3-rd header key-value records
puts f[1].headerKeyValueComment(1)
puts f[1].headerKeyValueComment(3)
puts f[1].headerKeyValueComment("TELESCOP")

#dump some header key-value records
puts f[1].header("TELESCOP")
puts f[1].header("RA_PNT").to_f

#retrieve header key-value record
f[1].headers.each { |headerRecord|
 puts headerRecord.keyword
}

FitsFile::header(indexOrKeyword) returns header record object (an instance of FitsHeaderRecord class). Values of header record objects can be obtained via usual cast methods such as to_s(), to_f(), to_i(), and so on.

Header key-value record can be modified by assigning new value to the header record object. If no entry is found with a provided keyword, a new entry will be created with keyword and value (and comment if specified).

#modify header records
f[1].header("TELESCOP") << "ASTRO-H"
f[1].setHeader("INSTRUME","SXS")
f[1].addHeader("NEWKEY",3.14159, "COMMENT")
Type of record can be automatically changed depending on the assigned value.
#modify header record with comment
f[1].header("TELESCOP") << [3.141592,"PI"]

Read Table Contents

FitsTableHDU consists of one or more FitsTableColumn objects which represent each column of the table. Data in a column can be accessed like ones contained in an array.

See readTable.rb in the example/ folder.

puts "TableHDU access example1:"
puts "============================================"
tableHDU=f.getHDU("SPECTRUM")
puts "TableHDU #{tableHDU.getHDUName()} has #{tableHDU.nColumns()} columns and #{tableHDU.nRows} rows."
tableHDU.columns.each {|column|
  puts column
}
puts "============================================"

This will result (with sampleTable.fits):

> ruby readTable.rb

... omitted ...

TableHDU access example1:

============================================

TableHDU SPECTRUM has 2 columns and 256 rows.
Column named "CHANNEL" = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ... (256 elements in total) ]
Column named "COUNTS" = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... (256 elements in total) ]

============================================

Another example is to use array accessor of FitsTableColumn. Index or range can be specified, e.g.

puts "TableHDU access example3:"
puts "============================================"
tableHDU=f.getHDU("SPECTRUM")
puts tableHDU["COUNTS"][100]
puts tableHDU["COUNTS"][100...120].join(",")
puts "============================================"
The above means "retrieve data of 101th-120th entries from the 'COUNTS' column contained in the 'SPECTRUM' HDU".

This will result:

============================================

115
115,109,115,84,87,95,79,111,76,71,93,102,93,81,88,77,73,86,71,78

============================================

Length of TableHDU (i.e. number of entries or number of rows) can be retrieved via FitsTableColumn.length() or its aliases:

  • nEntries
  • nRows
  • getNEntries
  • getNRows

Write Table Contents/Create New FITS File

See createNewTable.fits.

require "RubyFits"
include Fits

#create an empty column
column=FitsTableColumn.new

#set column name and format
column.initializeWithNameAndFormat("COUNTS","1J")

#set number of entries
column.resize(128)

#fill rows with (row number * 2).
for i in 0...column.nRows
	column[i]=i*2
end

#another example of filling rows
column[1..3]=[10,11,12]

#append the created column to a TableHDU
tableHDU=FitsTableHDU.new
tableHDU.resize(128)
tableHDU.appendColumn(column)
puts tableHDU

#append the create TableHDU to a FitsFile
f=FitsFile.new
f.append tableHDU

#Write to a file
f.saveAs("createNewTable.fits")

This will create a TableHDU with a column named "COUNTS" with a type of "1J" (i.e. 1 integer per row). Following the assignment, rows[1], row[2], and row[3] will have 10, 11, and 12, respectively.

Reading an Image HDU

FitsImageHDU handles access to ImageHDUs.

In the following example (copied from readImage.rb in the example/ folder), pHDU is the PrimarHDU os the "sampleTable.fits" file and its type is Image HDU (Primary HDU should be always ImageHDU). Although this sample FITS file does not contain meaningful values in the Primary HDU image, we can retrieve some pieces of information such as width, height, and pixel values.

require "RubyFits"
include Fits
f=FitsFile.new("sampleTable.fits")

#Primary HDU
pHDU=f.hdu(0)

puts pHDU
puts "Image type = #{pHDU.getTypeAsString()}"
puts "Image size = #{pHDU.getXSize} x #{pHDU.getYSize}"
puts "Pixel value:"
puts " (1,2) = #{pHDU.getPixelValue(1,2)}"
puts " (3,3) = #{pHDU.getPixelValue(3,3)}"
puts " (15,2) = #{pHDU.getPixelValue(15,2)}"
puts " (100,100) = #{pHDU.getPixelValue(100,100)} # <= this should be NaN because the pixel is outside the define size."

croppedImage=pHDU.section(1,2)

Creating an new Image HDU

The example code copied from newImage.rb shows how to create a new ImageHDU.

Note: In the current version of RubyFits, users have to call FitsImageHDU::imageHDU.constructImage(x,y,z,type) to actually construct an image with buffer allocated not only new() which creates an empty instance. This restriction is due to some limitation of SWIG related to the %rename attribute, and might be resolved in the future releases.

Type: type parameter should be one of the following values.

  • Fits::DOUBLE_T (64-bit double precision floating value)
  • Fits::FLOAT_T (32-bit single precision floating value)
  • Fits::LONG_T (32-bit signed integer)
  • Fits::LONGLONG_T (64-bit signed integer)
  • Fits::BYTE_T (8-bit signed integer)
  • Fits::SHORT_T (16-bit signed integer)
require "RubyFits"
include Fits

#Create an image HDU whose size is 100x100, and has type of DOUBLE_T 

puts Fits::DOUBLE_T
imageHDU=FitsImageHDU.new
imageHDU.constructImage(100,100,0,Fits::DOUBLE_T)
puts imageHDU.getHDUName
imageHDU.setHDUName("SampleImage")

puts imageHDU
puts "Image type = #{imageHDU.getTypeAsString()}"
puts "Image size = #{imageHDU.getXSize} x #{imageHDU.getYSize}"
puts "Setting a value to (50,50)"
imageHDU.setDouble(3.14159,50,50)
puts " (50,50) = #{imageHDU.getValue(50,50)}"

f=FitsFile.new
f.appendHDU(imageHDU)
f.saveAs("newImage.fits")
puts "Created image was saved to newImage.fits"

Variable-length-array-column access

Since August 2014, RubyFits provides easy-to-use interface for filling and reading variable-length-array (VLA) columns. VLA columns can be created by specifying, as the column data type, e.g. "PI" (int16_t VLA), "PJ" (int32_t VLA), "PE" (float VLA), "PD" (double VLA), and so on.

See examples/createNewVLATable.rb or examples/createNewTableFromTemplate.rb for detailed usage of VLA access methods.

Filling (writing) data to VLA columns

Once a VLA column is created in a Binary Table HDU, the column can be filled using the same ways as those for fixed-length columns, e.g.

# fill VLA column
hdu["VLA_INT_COLUMN"][0]=[1,2,3]
hdu["VLA_DOUBLE_COLUMN"][0]=[1.0,2.0,3.0]
hdu["VLA_INT_COLUMN"][1]=[4,5,6,7,8]
hdu["VLA_DOUBLE_COLUMN"][1]=[4.0,5.0,6.0,7.0,8.0]

Data type will be automatically determined based on the column type, and a Ruby-style Array will be converted to a C-style array (or C++ std::vector actually) internally, and written to the heap area of a Table HDU. When writing to a PE (VLA floating number column) or PD (VLA double-precision floating number column), create an array of Float by specifying floating-point numbers explicitly.

The following will result a conversion error.

# will result an error
hdu["VLA_DOUBLE_COLUMN"][0]=[1,2,3] #Array of Fixnum cannot be written to a VLA double column

One important note is that, when filling VLA columns using RubyFits, users should fill VLA columns in a sequential way, and the row index should only incremented (avoiding changing row index back and forth or randomly). All the VLA columns in an HDU shares the single heap area, and each row of one VLA column holds a data length and a pointer to the heap area where actual data for the row are stored, and therefore, out-of-order write access to rows of the VLA columns may cause corruption of the data in the heap.

The size of the heap area and the heap byte position pointer are internally managed so that users can sequentially call the assign method (column[rowIndex]=array) to fill the VLA columns.

Reading data from VLA columns

Data contained in the VLA columns can be easily read via the same methods as those used for fixed-length columns. Data will be returned as Ruby Array, and therefore, it is also very straightforward for users to retrieve the length of the data (i.e. via Array.length).

puts hdu["VLA_INT_COLUMN"][0]
# => displays e.g. [1,2,3]

Construct a FitsFile instance using template file

sfitsio accepts cfitsio-style template file to generated a new FitsFile instance, and so does RubyFits. FitsFile.constructFromTemplateString(str) returns a new FitsFile instance by constructing HDUs and columns based on a template specified as "str".

The following is the same code as contained in examples/createNewTableFromTemplate.rb, and shows how to construct a Binary Table HDU using a template string.

For template syntax, see CFITSIO Users Guide "Template Files" section.

require "RubyFits"
include Fits

templateString=<<EOS
XTENSION=BINTABLE
EXTNAME=TEST
TFORM#=I
TTYPE#=NUMBER

TFORM#=PD
TTYPE#=DOUBLE_ARRAY

COMMENT This is a sample FITS file generated by createNewTableFromTemplate.rb.
COMMENT The first column is of 16-bit signed integer type, and the second one
COMMENT is of variable-length double-precision floating-point number.
EOS

fitsFile=FitsFile.constructFromTemplateString(templateString)
hdu=fitsFile[1]

array=[]
nRows=100
hdu.resize(nRows)
for i in 0...nRows
	hdu["NUMBER"][i]=i
	array << Math.sqrt(i)
	hdu["DOUBLE_ARRAY"][i]=array
end

fitsFile.saveToFile("tableCreatedFromTemplate.fits")

Comment and Questions, misc

Comments, suggestions, and questions are welcome. Please send them to yuasa aaa astro.isas.jaxa.jp.

If you are interested in SpaceWire, see my another project "The open-source SpaceWire project" and "SpaceWire RMAP Library.

About

A Ruby FITS I/O library for astronomers and astrophysicists

Resources

Stars

Watchers

Forks

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •