/* * This file is part of libcxxsupport. * * libcxxsupport is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * libcxxsupport is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with libcxxsupport; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /* * libcxxsupport is being developed at the Max-Planck-Institut fuer Astrophysik * and financially supported by the Deutsches Zentrum fuer Luft- und Raumfahrt * (DLR). */ /* * This file contains the implementation of the FITS I/O helper class * used by the Planck LevelS package. * * Copyright (C) 2002 - 2009 Max-Planck-Society * Author: Martin Reinecke */ #include #include #include #include "fitsio.h" #include "fitshandle.h" #include "cxxutils.h" #include "safe_cast.h" #define FPTR (static_cast (fptr)) #define OFPTR (static_cast (orig.fptr)) using namespace std; namespace { template inline int fitsType(); template<> inline int fitsType () { return TFLOAT; } template<> inline int fitsType() { return TDOUBLE; } int type2bitpix (PDT type) { switch (type) { case PLANCK_FLOAT32: return FLOAT_IMG; case PLANCK_FLOAT64: return DOUBLE_IMG; default: planck_fail ("unsupported component type"); } } /*! Converts a FITS type code (i.e. the data type of a FITS column) to the corresponding Planck type code. */ PDT ftc2type (int ftc) { switch (ftc) { case TLOGICAL : return PLANCK_BOOL; case TBYTE : return PLANCK_INT8; case TSHORT : return PLANCK_INT16; case TINT : case TINT32BIT: return PLANCK_INT32; case TLONGLONG: return PLANCK_INT64; case TFLOAT : return PLANCK_FLOAT32; case TDOUBLE : return PLANCK_FLOAT64; case TSTRING : return PLANCK_STRING; default: planck_fail ("unsupported component type"); } } /*! Converts a Planck type code to the corresponding FITS type code (i.e. the data type of a FITS column). */ int type2ftc (PDT type) { switch (type) { case PLANCK_BOOL : return TLOGICAL; case PLANCK_INT8 : case PLANCK_UINT8 : return TBYTE; case PLANCK_INT16 : return TSHORT; case PLANCK_INT32 : return TINT; case PLANCK_INT64 : return TLONGLONG; case PLANCK_FLOAT32: return TFLOAT; case PLANCK_FLOAT64: return TDOUBLE; case PLANCK_STRING : return TSTRING; default: planck_fail ("unsupported component type"); } } const char *type2fitschar (PDT type) { switch (type) { case PLANCK_BOOL : return "L"; case PLANCK_FLOAT32: return "E"; case PLANCK_FLOAT64: return "D"; case PLANCK_INT8 : case PLANCK_UINT8 : return "B"; case PLANCK_INT16 : return "I"; case PLANCK_INT32 : return "J"; case PLANCK_INT64 : return "K"; case PLANCK_STRING : return "A"; default: planck_fail(string("unknown data type ")+type2string(type)); } } const char *type2asciiform (PDT type) { switch (type) { case PLANCK_FLOAT32: return "E14.7"; case PLANCK_FLOAT64: return "D23.15"; case PLANCK_UINT8 : return "I3"; case PLANCK_INT8 : return "I4"; case PLANCK_INT16 : return "I6"; case PLANCK_INT32 : return "I11"; case PLANCK_INT64 : return "I22"; default: planck_fail(string("unknown data type ")+type2string(type)); } } string fixkey (const string &key) { for (tsize m=0; mcolumns_.size())) return false; return true; } bool fitshandle::image_hdu () const { return hdutype_==IMAGE_HDU; } void fitshandle::init_image() { int naxis; fits_get_img_type (FPTR, &bitpix_, &status); fits_get_img_dim (FPTR, &naxis, &status); check_errors(); arr naxes(naxis); fits_get_img_sizell (FPTR, naxis, &naxes[0], &status); for (long m=0; m(data), &status); nrows_ = max(nrows_,offset+ndata); check_errors(); } void fitshandle::getKeyHelper(const string &name) const { if (status==KEY_NO_EXIST) { fits_clear_errmsg(); status=0; planck_fail("fitshandle::get_key(): key '"+name+"' not found"); } check_errors(); } void fitshandle::open (const string &fname) { clean_all(); fitsfile *ptr; fits_open_file(&ptr, fname.c_str(), READONLY, &status); fptr=ptr; check_errors(); init_data(); } void fitshandle::create (const string &fname) { clean_all(); fitsfile *ptr; fits_create_file(&ptr, fname.c_str(), &status); fptr=ptr; fits_write_imghdr(FPTR, 8, 0, 0, &status); // insert empty PHDU fits_write_date(FPTR, &status); check_errors(); init_data(); } // static void fitshandle::delete_file (const string &name) { fitsfile *ptr; int stat = 0; fits_open_file(&ptr, name.c_str(), READWRITE, &stat); fits_delete_file(ptr, &stat); if (stat==0) return; char msg[81]; fits_get_errstatus (stat, msg); cerr << msg << endl; while (fits_read_errmsg(msg)) cerr << msg << endl; planck_fail("FITS error"); } void fitshandle::goto_hdu (int hdu) { int curhdu; fits_get_hdu_num(FPTR,&curhdu); if (curhdu!=hdu) { fits_movabs_hdu(FPTR, hdu, &hdutype_, &status); check_errors(); init_data(); } } int fitshandle::num_hdus () const { int result; fits_get_num_hdus (FPTR, &result, &status); check_errors(); return result; } void fitshandle::insert_bintab (const vector &cols, const string &extname) { clean_data(); int ncol=cols.size(); arr2b ttype(ncol,81), tform(ncol,81), tunit(ncol,81); for (long m=0; m(extname.c_str()), 0, &status); check_errors(); init_data(); } void fitshandle::insert_asctab (const vector &cols, const string &extname) { clean_data(); int ncol=cols.size(); arr2b ttype(ncol,81), tform(ncol,81), tunit(ncol,81); for (long m=0; m(extname.c_str()), &status); check_errors(); init_data(); } void fitshandle::insert_image (PDT type, const vector &Axes) { clean_data(); arr tmpax(Axes.size()); for (long m=0; m void fitshandle::insert_image (PDT type, const arr2 &data) { clean_data(); arr tmpax(2); tmpax[0] = data.size2(); tmpax[1] = data.size1(); fits_insert_imgll (FPTR, type2bitpix(type), 2, &tmpax[0], &status); arr2 &tmparr = const_cast &> (data); fits_write_img (FPTR, fitsType(), 1, tmpax[0]*tmpax[1], &tmparr[0][0], &status); check_errors(); init_data(); } template void fitshandle::insert_image (PDT type, const arr2 &data); template void fitshandle::insert_image (PDT type, const arr2 &data); void fitshandle::write_checksum() { planck_assert(connected(),"handle not connected to a file"); fits_write_chksum (FPTR, &status); check_errors(); } const vector &fitshandle::axes() const { planck_assert(image_hdu(),"not connected to an image"); return axes_; } const string &fitshandle::colname(int i) const { planck_assert(table_hdu(i),"incorrect FITS table access"); return columns_[i-1].name(); } const string &fitshandle::colunit(int i) const { planck_assert(table_hdu(i),"incorrect FITS table access"); return columns_[i-1].unit(); } int64 fitshandle::repcount(int i) const { planck_assert(table_hdu(i),"incorrect FITS table access"); return columns_[i-1].repcount(); } PDT fitshandle::coltype(int i) const { planck_assert(table_hdu(i),"incorrect FITS table access"); return columns_[i-1].type(); } int fitshandle::ncols() const { planck_assert(table_hdu(1),"incorrect FITS table access"); return columns_.size(); } int64 fitshandle::nrows() const { planck_assert(table_hdu(1),"incorrect FITS table access"); return nrows_; } int64 fitshandle::nelems(int i) const { planck_assert(table_hdu(i),"incorrect FITS table access"); if (columns_[i-1].type()==PLANCK_STRING) return nrows_; return nrows_*columns_[i-1].repcount(); } int64 fitshandle::efficientChunkSize(int i) const { planck_assert(table_hdu(1),"incorrect FITS table access"); long int res; fits_get_rowsize(FPTR, &res, &status); planck_assert(res>=1,"bad recommended FITS chunk size"); check_errors(); return res*columns_[i-1].repcount(); } void fitshandle::get_all_keys(vector &keys) const { keys.clear(); char card[81]; const char *inclist[] = { "*" }; planck_assert(connected(),"handle not connected to a file"); fits_read_record (FPTR, 0, card, &status); check_errors(); while (true) { fits_find_nextkey (FPTR, const_cast(inclist), 1, 0, 0, card, &status); if (status!=0) break; if (fits_get_keyclass(card)==TYP_USER_KEY) { char keyname[80]; int dummy; fits_get_keyname(card, keyname, &dummy, &status); check_errors(); keys.push_back(trim(keyname)); } check_errors(); } if (status==KEY_NO_EXIST) { fits_clear_errmsg(); status=0; } check_errors(); } void fitshandle::set_key_void (const string &key, const void *value, PDT type, const string &comment) { planck_assert(connected(),"handle not connected to a file"); string key2 = fixkey(key); switch (type) { case PLANCK_INT8: case PLANCK_UINT8: case PLANCK_INT16: case PLANCK_INT32: case PLANCK_INT64: case PLANCK_FLOAT32: case PLANCK_FLOAT64: fits_update_key (FPTR, type2ftc(type), const_cast(key2.c_str()), const_cast(value), const_cast(comment.c_str()), &status); break; case PLANCK_BOOL: { int val = *(static_cast(value)); fits_update_key (FPTR, TLOGICAL, const_cast(key2.c_str()), &val, const_cast(comment.c_str()), &status); break; } case PLANCK_STRING: { string val = *(static_cast(value)); fits_update_key_longstr (FPTR, const_cast(key2.c_str()), const_cast(val.c_str()), const_cast(comment.c_str()), &status); break; } default: planck_fail ("unsupported data type in set_key_void()"); } check_errors(); } void fitshandle::get_key_void (const string &name, void *value, PDT type) const { planck_assert(connected(),"handle not connected to a file"); switch (type) { case PLANCK_INT8: case PLANCK_UINT8: case PLANCK_INT16: case PLANCK_INT32: case PLANCK_INT64: case PLANCK_FLOAT32: case PLANCK_FLOAT64: fits_read_key (FPTR, type2ftc(type), const_cast(name.c_str()), value, 0, &status); getKeyHelper(name); break; case PLANCK_BOOL: { int val; fits_read_key (FPTR, TLOGICAL, const_cast(name.c_str()), &val, 0, &status); getKeyHelper(name); *(static_cast(value))=val; break; } case PLANCK_STRING: { char *tmp=0; fits_read_key_longstr (FPTR, const_cast(name.c_str()), &tmp, 0, &status); getKeyHelper(name); *(static_cast(value))=tmp; if (tmp) free(tmp); break; } default: planck_fail ("unsupported data type in get_key_void()"); } check_errors(); } void fitshandle::delete_key (const string &name) { planck_assert(connected(),"handle not connected to a file"); fits_delete_key (FPTR, const_cast(name.c_str()), &status); check_errors(); } void fitshandle::add_comment(const string &comment) { planck_assert(connected(),"handle not connected to a file"); fits_write_comment(FPTR,const_cast(comment.c_str()),&status); check_errors(); } bool fitshandle::key_present(const string &name) const { char card[81]; planck_assert(connected(),"handle not connected to a file"); fits_read_card(FPTR, const_cast(name.c_str()), card, &status); if (status==KEY_NO_EXIST) { fits_clear_errmsg(); status=0; return false; } check_errors(); return true; } void fitshandle::assert_pdmtype (const string &pdmtype) const { string type; get_key("PDMTYPE",type); if (pdmtype==type) return; cerr << "PDMTYPE " << pdmtype << " expected, but found " << type << endl; } void fitshandle::read_column_raw_void (int colnum, void *data, PDT type, int64 num, int64 offset) const { switch (type) { case PLANCK_INT8: case PLANCK_UINT8: case PLANCK_INT16: case PLANCK_INT32: case PLANCK_INT64: case PLANCK_FLOAT32: case PLANCK_FLOAT64: case PLANCK_BOOL: read_col (colnum, data, num, type, offset); break; case PLANCK_STRING: { string *data2 = static_cast (data); planck_assert(table_hdu(colnum),"incorrect FITS table access"); planck_assert (num<=(nrows_-offset), "read_column(): array too large"); arr2b tdata(safe_cast(num), safe_cast(columns_[colnum-1].repcount()+1)); fits_read_col (FPTR, TSTRING, colnum, offset+1, 1, num, 0, tdata.p0(), 0, &status); check_errors(); for (long m=0;m (data); planck_assert(table_hdu(colnum),"incorrect FITS table access"); tsize stringlen = safe_cast(columns_[colnum-1].repcount()+1); arr2b tdata(safe_cast(num), stringlen); for (long m=0;m(data), &status); check_errors(); } void fitshandle::write_subimage_void (const void *data, PDT type, tsize sz, int64 offset) { planck_assert(image_hdu(),"not connected to an image"); fits_write_img (FPTR, type2ftc(type), 1+offset, sz, const_cast(data), &status); check_errors(); } template void fitshandle::read_image (arr2 &data) const { planck_assert(image_hdu(),"not connected to an image"); planck_assert (axes_.size()==2, "wrong number of dimensions"); data.alloc(safe_cast(axes_[0]), safe_cast(axes_[1])); fits_read_img (FPTR, fitsType(), 1, axes_[0]*axes_[1], 0, &data[0][0], 0, &status); check_errors(); } template void fitshandle::read_image (arr2 &data) const; template void fitshandle::read_image (arr2 &data) const; template void fitshandle::read_image (arr3 &data) const { planck_assert(image_hdu(),"not connected to an image"); planck_assert (axes_.size()==3, "wrong number of dimensions"); data.alloc(safe_cast(axes_[0]), safe_cast(axes_[1]), safe_cast(axes_[2])); fits_read_img (FPTR, fitsType(), 1, axes_[0]*axes_[1]*axes_[2], 0, &data(0,0,0), 0, &status); check_errors(); } template void fitshandle::read_image (arr3 &data) const; template void fitshandle::read_image (arr3 &data) const; template void fitshandle::read_subimage (arr2 &data, int xl, int yl) const { planck_assert(image_hdu(),"not connected to an image"); planck_assert (axes_.size()==2, "wrong number of dimensions"); for (tsize m=0; m(), (xl+m)*axes_[1]+yl+1, data.size2(), 0, &data[m][0], 0, &status); check_errors(); } template void fitshandle::read_subimage (arr2 &data, int xl, int yl) const; template void fitshandle::read_subimage (arr2 &data, int xl, int yl) const; void fitshandle::read_subimage_void (void *data, PDT type, tsize ndata, int64 offset) const { planck_assert(image_hdu(),"not connected to an image"); fits_read_img (FPTR, type2ftc(type), 1+offset, ndata, 0, data, 0, &status); check_errors(); } namespace { class cfitsio_checker { public: cfitsio_checker() { float fitsversion; planck_assert(fits_get_version(&fitsversion), "error calling fits_get_version()"); int v_header = nearest(1000.*CFITSIO_VERSION), v_library = nearest(1000.*fitsversion); if (v_header!=v_library) cerr << endl << "WARNING: version mismatch between CFITSIO header (v" << dataToString(v_header*0.001) << ") and linked library (v" << dataToString(v_library*0.001) << ")." << endl << endl; } }; cfitsio_checker Cfitsio_Checker; } // unnamed namespace