LSST Applications g02d81e74bb+86cf3d8bc9,g180d380827+7a4e862ed4,g2079a07aa2+86d27d4dc4,g2305ad1205+e1ca1c66fa,g29320951ab+012e1474a1,g295015adf3+341ea1ce94,g2bbee38e9b+0e5473021a,g337abbeb29+0e5473021a,g33d1c0ed96+0e5473021a,g3a166c0a6a+0e5473021a,g3ddfee87b4+c429d67c83,g48712c4677+f88676dd22,g487adcacf7+27e1e21933,g50ff169b8f+96c6868917,g52b1c1532d+585e252eca,g591dd9f2cf+b41db86c35,g5a732f18d5+53520f316c,g64a986408d+86cf3d8bc9,g858d7b2824+86cf3d8bc9,g8a8a8dda67+585e252eca,g99cad8db69+84912a7fdc,g9ddcbc5298+9a081db1e4,ga1e77700b3+15fc3df1f7,ga8c6da7877+a2b54eae19,gb0e22166c9+60f28cb32d,gba4ed39666+c2a2e4ac27,gbb8dafda3b+6681f309db,gc120e1dc64+f0fcc2f6d8,gc28159a63d+0e5473021a,gcf0d15dbbd+c429d67c83,gdaeeff99f8+f9a426f77a,ge6526c86ff+0433e6603d,ge79ae78c31+0e5473021a,gee10cc3b42+585e252eca,gff1a9f87cc+86cf3d8bc9,w.2024.17
LSST Data Management Base Package
Loading...
Searching...
No Matches
Public Types | Public Member Functions | Public Attributes | List of all members
lsst::afw::fits::Fits Class Reference

A simple struct that combines the two arguments that must be passed to most cfitsio routines and contains thin and/or templated wrappers around common cfitsio routines. More...

#include <fits.h>

Public Types

enum  BehaviorFlags { AUTO_CLOSE = 0x01 , AUTO_CHECK = 0x02 }
 

Public Member Functions

std::string getFileName () const
 Return the file name associated with the FITS object or "<unknown>" if there is none.
 
int getHdu ()
 Return the current HDU (0-indexed; 0 is the Primary HDU).
 
void setHdu (int hdu, bool relative=false)
 Set the current HDU.
 
void setHdu (std::string const &name, HduType hdutype=HduType::ANY, int hduver=0)
 Set the current HDU using its name, version and type.
 
int countHdus ()
 Return the number of HDUs in the file.
 
template<typename T >
void updateKey (std::string const &key, T const &value, std::string const &comment)
 Set a FITS header key, editing if it already exists and appending it if not.
 
void updateKey (std::string const &key, char const *value, std::string const &comment)
 
template<typename T >
void updateKey (std::string const &key, T const &value)
 
void updateKey (std::string const &key, char const *value)
 
template<typename T >
void writeKey (std::string const &key, T const &value, std::string const &comment)
 Add a FITS header key to the bottom of the header.
 
void writeKey (std::string const &key, char const *value, std::string const &comment)
 
template<typename T >
void writeKey (std::string const &key, T const &value)
 
void writeKey (std::string const &key, char const *value)
 
template<typename T >
void updateColumnKey (std::string const &prefix, int n, T const &value, std::string const &comment)
 Update a key of the form XXXXXnnn, where XXXXX is the prefix and nnn is a column number.
 
void updateColumnKey (std::string const &prefix, int n, char const *value, std::string const &comment)
 
template<typename T >
void updateColumnKey (std::string const &prefix, int n, T const &value)
 
void updateColumnKey (std::string const &prefix, int n, char const *value)
 
template<typename T >
void writeColumnKey (std::string const &prefix, int n, T const &value, std::string const &comment)
 Write a key of the form XXXXXnnn, where XXXXX is the prefix and nnn is a column number.
 
void writeColumnKey (std::string const &prefix, int n, char const *value, std::string const &comment)
 
template<typename T >
void writeColumnKey (std::string const &prefix, int n, T const &value)
 
void writeColumnKey (std::string const &prefix, int n, char const *value)
 
void writeMetadata (daf::base::PropertySet const &metadata)
 Read a FITS header into a PropertySet or PropertyList.
 
void readMetadata (daf::base::PropertySet &metadata, bool strip=false)
 Read a FITS header into a PropertySet or PropertyList.
 
template<typename T >
void readKey (std::string const &key, T &value)
 Read a FITS header key into the given reference.
 
void forEachKey (HeaderIterationFunctor &functor)
 Call a polymorphic functor for every key in the header.
 
void createEmpty ()
 Create an empty image HDU with NAXIS=0 at the end of the file.
 
template<typename PixelT , int N>
void createImage (ndarray::Vector< ndarray::Size, N > const &shape)
 Create an image with pixel type provided by the given explicit PixelT template parameter and shape defined by an ndarray index.
 
template<int N>
void createImage (int bitpix, ndarray::Vector< ndarray::Size, N > const &shape)
 
template<typename PixelT >
void createImage (long x, long y)
 Create a 2-d image with pixel type provided by the given explicit PixelT template parameter.
 
template<typename T , int N, int C>
void writeImage (ndarray::Array< T const, N, C > const &array)
 Write an ndarray::Array to a FITS image HDU.
 
template<typename T >
void writeImage (image::ImageBase< T > const &image, ImageWriteOptions const &options, daf::base::PropertySet const *header=nullptr, image::Mask< image::MaskPixel > const *mask=nullptr)
 Write an image to FITS.
 
int getImageDim ()
 Return the number of dimensions in the current HDU.
 
template<int N>
ndarray::Vector< ndarray::Size, N > getImageShape ()
 Return the shape of the current (image) HDU.
 
template<typename T >
bool checkImageType ()
 Return true if the current HDU is compatible with the given pixel type.
 
std::string getImageDType ()
 Return the numpy dtype equivalent of the image pixel type (e.g.
 
template<typename T , int N>
void readImage (ndarray::Array< T, N, N > const &array, ndarray::Vector< int, N > const &offset)
 Read an array from a FITS image.
 
void createTable ()
 Create a new binary table extension.
 
template<typename T >
int addColumn (std::string const &ttype, int size, std::string const &comment)
 Add a column to a table.
 
template<typename T >
int addColumn (std::string const &ttype, int size)
 Add a column to a table.
 
std::size_t addRows (std::size_t nRows)
 Append rows to a table, and return the index of the first new row.
 
std::size_t countRows ()
 Return the number of row in a table.
 
template<typename T >
void writeTableArray (std::size_t row, int col, int nElements, T const *value)
 Write an array value to a binary table.
 
template<typename T >
void writeTableScalar (std::size_t row, int col, T value)
 Write a scalar value to a binary table.
 
void writeTableScalar (std::size_t row, int col, std::string const &value)
 Write a string to a binary table.
 
template<typename T >
void readTableArray (std::size_t row, int col, int nElements, T *value)
 Read an array value from a binary table.
 
template<typename T >
void readTableScalar (std::size_t row, int col, T &value)
 Read an array scalar from a binary table.
 
void readTableScalar (std::size_t row, int col, std::string &value, bool isVariableLength)
 Read a string from a binary table.
 
long getTableArraySize (int col)
 Return the size of an array column.
 
long getTableArraySize (std::size_t row, int col)
 Return the size of an variable-length array field.
 
 Fits ()
 Default constructor; set all data members to 0.
 
 Fits (std::string const &filename, std::string const &mode, int behavior)
 Open or create a FITS file from disk.
 
 Fits (MemFileManager &manager, std::string const &mode, int behavior)
 Open or create a FITS file from an in-memory file.
 
void closeFile ()
 Close a FITS file.
 
void setImageCompression (ImageCompressionOptions const &options)
 Set compression options for writing FITS images.
 
ImageCompressionOptions getImageCompression ()
 Return the current image compression settings.
 
bool checkCompressedImagePhu ()
 Go to the first image header in the FITS file.
 
 ~Fits ()
 
 Fits (const Fits &)=delete
 
Fitsoperator= (const Fits &)=delete
 
 Fits (Fits &&)=delete
 
Fitsoperator= (Fits &&)=delete
 

Public Attributes

void * fptr
 
int status
 
int behavior
 

Detailed Description

A simple struct that combines the two arguments that must be passed to most cfitsio routines and contains thin and/or templated wrappers around common cfitsio routines.

This is NOT intended to be an object-oriented C++ wrapper around cfitsio; it's simply a thin layer that saves a lot of repetition, const/reinterpret casts, and replaces void pointer args and type codes with templates and overloads.

Like a cfitsio pointer, a Fits object always considers one HDU the "active" one, and most operations will be applied to that HDU.

All member functions are non-const because they may modify the 'status' data member.

Note
All functions that take a row or column number below are 0-indexed; the internal cfitsio calls are all 1-indexed.

Definition at line 308 of file fits.h.

Member Enumeration Documentation

◆ BehaviorFlags

Enumerator
AUTO_CLOSE 
AUTO_CHECK 

Definition at line 317 of file fits.h.

317 {
318 AUTO_CLOSE = 0x01, // Close files when the Fits object goes out of scope if fptr != NULL
319 AUTO_CHECK = 0x02 // Call LSST_FITS_CHECK_STATUS after every cfitsio call
320 };

Constructor & Destructor Documentation

◆ Fits() [1/5]

lsst::afw::fits::Fits::Fits ( )
inline

Default constructor; set all data members to 0.

Definition at line 631 of file fits.h.

631: fptr(nullptr), status(0), behavior(0) {}

◆ Fits() [2/5]

lsst::afw::fits::Fits::Fits ( std::string const & filename,
std::string const & mode,
int behavior )

Open or create a FITS file from disk.

Definition at line 1572 of file fits.cc.

1573 : fptr(nullptr), status(0), behavior(behavior_) {
1574 if (mode == "r" || mode == "rb") {
1575 fits_open_file(reinterpret_cast<fitsfile **>(&fptr), const_cast<char *>(filename.c_str()), READONLY,
1576 &status);
1577 } else if (mode == "w" || mode == "wb") {
1578 std::filesystem::remove(filename); // cfitsio doesn't like over-writing files
1579 fits_create_file(reinterpret_cast<fitsfile **>(&fptr), const_cast<char *>(filename.c_str()), &status);
1580 } else if (mode == "a" || mode == "ab") {
1581 fits_open_file(reinterpret_cast<fitsfile **>(&fptr), const_cast<char *>(filename.c_str()), READWRITE,
1582 &status);
1583 int nHdu = 0;
1584 fits_get_num_hdus(reinterpret_cast<fitsfile *>(fptr), &nHdu, &status);
1585 fits_movabs_hdu(reinterpret_cast<fitsfile *>(fptr), nHdu, nullptr, &status);
1586 if ((behavior & AUTO_CHECK) && (behavior & AUTO_CLOSE) && (status) && (fptr)) {
1587 // We're about to throw an exception, and the destructor won't get called
1588 // because we're in the constructor, so cleanup here first.
1589 int tmpStatus = 0;
1590 fits_close_file(reinterpret_cast<fitsfile *>(fptr), &tmpStatus);
1591 }
1592 } else {
1593 throw LSST_EXCEPT(
1594 FitsError,
1595 (boost::format("Invalid mode '%s' given when opening file '%s'") % mode % filename).str());
1596 }
1597 if (behavior & AUTO_CHECK) {
1598 LSST_FITS_CHECK_STATUS(*this, boost::format("Opening file '%s' with mode '%s'") % filename % mode);
1599 }
1600}
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
Definition Exception.h:48
#define LSST_FITS_CHECK_STATUS(fitsObj,...)
Throw a FitsError exception if the status of the given Fits object is nonzero.
Definition fits.h:111

◆ Fits() [3/5]

lsst::afw::fits::Fits::Fits ( MemFileManager & manager,
std::string const & mode,
int behavior )

Open or create a FITS file from an in-memory file.

Definition at line 1602 of file fits.cc.

1603 : fptr(nullptr), status(0), behavior(behavior_) {
1604 using Reallocator = void *(*)(void *, std::size_t);
1605 // It's a shame this logic is essentially a duplicate of above, but the innards are different enough
1606 // we can't really reuse it.
1607 if (mode == "r" || mode == "rb") {
1608 fits_open_memfile(reinterpret_cast<fitsfile **>(&fptr), "unused", READONLY, &manager._ptr,
1609 &manager._len, 0, nullptr, // no reallocator or deltasize necessary for READONLY
1610 &status);
1611 } else if (mode == "w" || mode == "wb") {
1612 Reallocator reallocator = nullptr;
1613 if (manager._managed) reallocator = &std::realloc;
1614 fits_create_memfile(reinterpret_cast<fitsfile **>(&fptr), &manager._ptr, &manager._len, 0,
1615 reallocator, // use default deltasize
1616 &status);
1617 } else if (mode == "a" || mode == "ab") {
1618 Reallocator reallocator = nullptr;
1619 if (manager._managed) reallocator = &std::realloc;
1620 fits_open_memfile(reinterpret_cast<fitsfile **>(&fptr), "unused", READWRITE, &manager._ptr,
1621 &manager._len, 0, reallocator, &status);
1622 int nHdu = 0;
1623 fits_get_num_hdus(reinterpret_cast<fitsfile *>(fptr), &nHdu, &status);
1624 fits_movabs_hdu(reinterpret_cast<fitsfile *>(fptr), nHdu, nullptr, &status);
1625 if ((behavior & AUTO_CHECK) && (behavior & AUTO_CLOSE) && (status) && (fptr)) {
1626 // We're about to throw an exception, and the destructor won't get called
1627 // because we're in the constructor, so cleanup here first.
1628 int tmpStatus = 0;
1629 fits_close_file(reinterpret_cast<fitsfile *>(fptr), &tmpStatus);
1630 }
1631 } else {
1632 throw LSST_EXCEPT(FitsError,
1633 (boost::format("Invalid mode '%s' given when opening memory file at '%s'") % mode %
1634 manager._ptr)
1635 .str());
1636 }
1637 if (behavior & AUTO_CHECK) {
1639 *this, boost::format("Opening memory file at '%s' with mode '%s'") % manager._ptr % mode);
1640 }
1641}
T realloc(T... args)

◆ ~Fits()

lsst::afw::fits::Fits::~Fits ( )
inline

Definition at line 659 of file fits.h.

659 {
660 if ((fptr) && (behavior & AUTO_CLOSE)) closeFile();
661 }
void closeFile()
Close a FITS file.
Definition fits.cc:1643

◆ Fits() [4/5]

lsst::afw::fits::Fits::Fits ( const Fits & )
delete

◆ Fits() [5/5]

lsst::afw::fits::Fits::Fits ( Fits && )
delete

Member Function Documentation

◆ addColumn() [1/2]

template<typename T >
int lsst::afw::fits::Fits::addColumn ( std::string const & ttype,
int size )

Add a column to a table.

If size <= 0, the field will be a variable length array, with max set by (-size), or left unknown if size == 0.

Definition at line 1146 of file fits.cc.

1146 {
1147 int nCols = 0;
1148 fits_get_num_cols(reinterpret_cast<fitsfile *>(fptr), &nCols, &status);
1149 std::string tform = makeColumnFormat<T>(size);
1150 fits_insert_col(reinterpret_cast<fitsfile *>(fptr), nCols + 1, const_cast<char *>(ttype.c_str()),
1151 const_cast<char *>(tform.c_str()), &status);
1152 if (behavior & AUTO_CHECK) {
1153 LSST_FITS_CHECK_STATUS(*this, boost::format("Adding column '%s' with size %d") % ttype % size);
1154 }
1155 return nCols;
1156}
T c_str(T... args)

◆ addColumn() [2/2]

template<typename T >
int lsst::afw::fits::Fits::addColumn ( std::string const & ttype,
int size,
std::string const & comment )

Add a column to a table.

If size <= 0, the field will be a variable length array, with max set by (-size), or left unknown if size == 0.

Definition at line 1159 of file fits.cc.

1159 {
1160 int nCols = addColumn<T>(ttype, size);
1161 updateColumnKey("TTYPE", nCols, ttype, comment);
1162 if (behavior & AUTO_CHECK) {
1163 LSST_FITS_CHECK_STATUS(*this, boost::format("Adding column '%s' with size %d") % ttype % size);
1164 }
1165 return nCols;
1166}
void updateColumnKey(std::string const &prefix, int n, T const &value, std::string const &comment)
Update a key of the form XXXXXnnn, where XXXXX is the prefix and nnn is a column number.
Definition fits.cc:710

◆ addRows()

std::size_t lsst::afw::fits::Fits::addRows ( std::size_t nRows)

Append rows to a table, and return the index of the first new row.

Definition at line 1168 of file fits.cc.

1168 {
1169 long first = 0;
1170 fits_get_num_rows(reinterpret_cast<fitsfile *>(fptr), &first, &status);
1171 fits_insert_rows(reinterpret_cast<fitsfile *>(fptr), first, nRows, &status);
1172 if (behavior & AUTO_CHECK) {
1173 LSST_FITS_CHECK_STATUS(*this, boost::format("Adding %d rows to binary table") % nRows);
1174 }
1175 return first;
1176}

◆ checkCompressedImagePhu()

bool lsst::afw::fits::Fits::checkCompressedImagePhu ( )

Go to the first image header in the FITS file.

If a single image is written compressed, it appears as an extension, rather than the primary HDU (PHU). This method is useful before reading an image, as it checks whether we are positioned on an empty PHU and if the next HDU is a compressed image; if so, it leaves the file pointer on the compresed image, ready for reading.

Definition at line 1767 of file fits.cc.

1767 {
1768 auto fits = reinterpret_cast<fitsfile *>(fptr);
1769 if (getHdu() != 0 || countHdus() == 1) {
1770 return false; // Can't possibly be the PHU leading a compressed image
1771 }
1772 // Check NAXIS = 0
1773 int naxis;
1774 fits_get_img_dim(fits, &naxis, &status);
1775 if (behavior & AUTO_CHECK) {
1776 LSST_FITS_CHECK_STATUS(*this, "Checking NAXIS of PHU");
1777 }
1778 if (naxis != 0) {
1779 return false;
1780 }
1781 // Check first extension (and move back there when we're done if we're not compressed)
1782 HduMoveGuard move(*this, 1);
1783 bool isCompressed = fits_is_compressed_image(fits, &status);
1784 if (behavior & AUTO_CHECK) {
1785 LSST_FITS_CHECK_STATUS(*this, "Checking compression");
1786 }
1787 if (isCompressed) {
1788 move.disable();
1789 }
1790 return isCompressed;
1791}
int countHdus()
Return the number of HDUs in the file.
Definition fits.cc:553
int getHdu()
Return the current HDU (0-indexed; 0 is the Primary HDU).
Definition fits.cc:518
T move(T... args)

◆ checkImageType()

template<typename T >
bool lsst::afw::fits::Fits::checkImageType ( )

Return true if the current HDU is compatible with the given pixel type.

This takes into account the BSCALE and BZERO keywords, which can allow integer images to be interpreted as floating point.

Definition at line 1455 of file fits.cc.

1455 {
1456 int imageType = 0;
1457 fits_get_img_equivtype(reinterpret_cast<fitsfile *>(fptr), &imageType, &status);
1458 if (behavior & AUTO_CHECK) LSST_FITS_CHECK_STATUS(*this, "Getting image type");
1460 if (imageType < 0) {
1461 return false; // can't represent floating-point with integer
1462 }
1464 if (isFitsImageTypeSigned(imageType)) {
1465 return FitsBitPix<T>::CONSTANT >= imageType;
1466 } else {
1467 // need extra bits to safely convert unsigned to signed
1468 return FitsBitPix<T>::CONSTANT > imageType;
1469 }
1470 } else {
1471 if (!isFitsImageTypeSigned(imageType)) {
1472 return FitsBitPix<T>::CONSTANT >= imageType;
1473 } else if (imageType == LONGLONG_IMG) {
1474 // workaround for CFITSIO not recognizing uint64 as
1475 // unsigned
1476 return FitsBitPix<T>::CONSTANT >= imageType;
1477 } else {
1478 return false;
1479 }
1480 }
1481 }
1482 // we allow all conversions to float and double, even if they lose precision
1483 return true;
1484}

◆ closeFile()

void lsst::afw::fits::Fits::closeFile ( )

Close a FITS file.

Definition at line 1643 of file fits.cc.

1643 {
1644 fits_close_file(reinterpret_cast<fitsfile *>(fptr), &status);
1645 fptr = nullptr;
1646}

◆ countHdus()

int lsst::afw::fits::Fits::countHdus ( )

Return the number of HDUs in the file.

Definition at line 553 of file fits.cc.

553 {
554 int n = 0;
555 fits_get_num_hdus(reinterpret_cast<fitsfile *>(fptr), &n, &status);
556 if (behavior & AUTO_CHECK) {
557 LSST_FITS_CHECK_STATUS(*this, "Getting number of HDUs in file.");
558 }
559 return n;
560}

◆ countRows()

std::size_t lsst::afw::fits::Fits::countRows ( )

Return the number of row in a table.

Definition at line 1178 of file fits.cc.

1178 {
1179 long r = 0;
1180 fits_get_num_rows(reinterpret_cast<fitsfile *>(fptr), &r, &status);
1181 if (behavior & AUTO_CHECK) {
1182 LSST_FITS_CHECK_STATUS(*this, "Checking how many rows are in table");
1183 }
1184 return r;
1185}

◆ createEmpty()

void lsst::afw::fits::Fits::createEmpty ( )

Create an empty image HDU with NAXIS=0 at the end of the file.

This is primarily useful to force the first "real" HDU to be an extension HDU by creating an empty Primary HDU. The new HDU is set as the active one.

Definition at line 1259 of file fits.cc.

1259 {
1260 long naxes = 0;
1261 fits_create_img(reinterpret_cast<fitsfile *>(fptr), 8, 0, &naxes, &status);
1262 if (behavior & AUTO_CHECK) {
1263 LSST_FITS_CHECK_STATUS(*this, "Creating empty image HDU");
1264 }
1265}

◆ createImage() [1/3]

template<int N>
void lsst::afw::fits::Fits::createImage ( int bitpix,
ndarray::Vector< ndarray::Size, N > const & shape )
inline

Definition at line 471 of file fits.h.

471 {
472 ndarray::Vector<long, N> nAxes(shape.reverse());
473 createImageImpl(bitpix, N, nAxes.elems);
474 }

◆ createImage() [2/3]

template<typename PixelT >
void lsst::afw::fits::Fits::createImage ( long x,
long y )
inline

Create a 2-d image with pixel type provided by the given explicit PixelT template parameter.

The new image will be in a new HDU at the end of the file, which may be the Primary HDU if the FITS file is empty.

Definition at line 483 of file fits.h.

483 {
484 long naxes[2] = {x, y};
485 createImageImpl(detail::Bitpix<PixelT>::value, 2, naxes);
486 }
int y
Definition SpanSet.cc:48

◆ createImage() [3/3]

template<typename PixelT , int N>
void lsst::afw::fits::Fits::createImage ( ndarray::Vector< ndarray::Size, N > const & shape)
inline

Create an image with pixel type provided by the given explicit PixelT template parameter and shape defined by an ndarray index.

Note
The shape parameter is ordered fastest-dimension last (i.e. [y, x]) as is conventional with ndarray.

The new image will be in a new HDU at the end of the file, which may be the Primary HDU if the FITS file is empty.

Definition at line 465 of file fits.h.

465 {
466 ndarray::Vector<long, N> nAxes(shape.reverse());
467 createImageImpl(detail::Bitpix<PixelT>::value, N, nAxes.elems);
468 }

◆ createTable()

void lsst::afw::fits::Fits::createTable ( )

Create a new binary table extension.

Definition at line 1136 of file fits.cc.

1136 {
1137 char *ttype = nullptr;
1138 char *tform = nullptr;
1139 fits_create_tbl(reinterpret_cast<fitsfile *>(fptr), BINARY_TBL, 0, 0, &ttype, &tform, nullptr, nullptr, &status);
1140 if (behavior & AUTO_CHECK) {
1141 LSST_FITS_CHECK_STATUS(*this, "Creating binary table");
1142 }
1143}

◆ forEachKey()

void lsst::afw::fits::Fits::forEachKey ( HeaderIterationFunctor & functor)

Call a polymorphic functor for every key in the header.

Each value is passed in as a string, and the single quotes that mark an actual string value are not removed (neither are extra spaces). However, long strings that make use of the CONTINUE keyword are concatenated to look as if they were on a single line.

Definition at line 800 of file fits.cc.

800 {
801 char key[81]; // allow for terminating NUL
802 char value[81];
803 char comment[81];
804 int nKeys = 0;
805 fits_get_hdrspace(reinterpret_cast<fitsfile *>(fptr), &nKeys, nullptr, &status);
806 std::string keyStr;
807 std::string valueStr;
808 std::string commentStr;
809 int i = 1;
810 while (i <= nKeys) {
811 fits_read_keyn(reinterpret_cast<fitsfile *>(fptr), i, key, value, comment, &status);
812 // fits_read_keyn does not convert the key case on read, like other fits methods in cfitsio>=3.38
813 // We uppercase to try to be more consistent.
814 std::string upperKey(key);
815 boost::to_upper(upperKey);
816 if (upperKey.compare(key) != 0){
817 LOGLS_DEBUG("lsst.afw.fits",
818 boost::format("In %s, standardizing key '%s' to uppercase '%s' on read.") %
819 BOOST_CURRENT_FUNCTION % key % upperKey);
820 }
821 keyStr = upperKey;
822 valueStr = value;
823 commentStr = comment;
824 ++i;
825 while (valueStr.size() > 2 && valueStr[valueStr.size() - 2] == '&' && i <= nKeys) {
826 // we're using key to hold the entire record here; the actual key is safe in keyStr
827 fits_read_record(reinterpret_cast<fitsfile *>(fptr), i, key, &status);
828 if (strncmp(key, "CONTINUE", 8) != 0) {
829 // require both trailing '&' and CONTINUE to invoke long-string handling
830 break;
831 }
832 std::string card = key;
833 valueStr.erase(valueStr.size() - 2);
834 std::size_t firstQuote = card.find('\'');
835 if (firstQuote == std::string::npos) {
836 throw LSST_EXCEPT(
837 FitsError,
839 fptr, status,
840 boost::format("Invalid CONTINUE at header key %d: \"%s\".") % i % card));
841 }
842 std::size_t lastQuote = card.find('\'', firstQuote + 1);
843 if (lastQuote == std::string::npos) {
844 throw LSST_EXCEPT(
845 FitsError,
847 fptr, status,
848 boost::format("Invalid CONTINUE at header key %d: \"%s\".") % i % card));
849 }
850 valueStr += card.substr(firstQuote + 1, lastQuote - firstQuote);
851 std::size_t slash = card.find('/', lastQuote + 1);
852 if (slash != std::string::npos) {
853 commentStr += strip(card.substr(slash + 1));
854 }
855 ++i;
856 }
857 if (behavior & AUTO_CHECK) {
858 LSST_FITS_CHECK_STATUS(*this, boost::format("Reading key '%s'") % keyStr);
859 }
860 functor(keyStr, valueStr, commentStr);
861 }
862}
#define LOGLS_DEBUG(logger, message)
Log a debug-level message using an iostream-based interface.
Definition Log.h:619
T erase(T... args)
T find(T... args)
bool strip
Definition fits.cc:930
std::string makeErrorMessage(std::string const &fileName="", int status=0, std::string const &msg="")
Return an error message reflecting FITS I/O errors.
Definition fits.cc:431
T size(T... args)
T strncmp(T... args)
T substr(T... args)

◆ getFileName()

std::string lsst::afw::fits::Fits::getFileName ( ) const

Return the file name associated with the FITS object or "<unknown>" if there is none.

Definition at line 509 of file fits.cc.

509 {
510 std::string fileName = "<unknown>";
511 fitsfile *fd = reinterpret_cast<fitsfile *>(fptr);
512 if (fd != nullptr && fd->Fptr != nullptr && fd->Fptr->filename != nullptr) {
513 fileName = fd->Fptr->filename;
514 }
515 return fileName;
516}

◆ getHdu()

int lsst::afw::fits::Fits::getHdu ( )

Return the current HDU (0-indexed; 0 is the Primary HDU).

Definition at line 518 of file fits.cc.

518 {
519 int n = 1;
520 fits_get_hdu_num(reinterpret_cast<fitsfile *>(fptr), &n);
521 return n - 1;
522}

◆ getImageCompression()

ImageCompressionOptions lsst::afw::fits::Fits::getImageCompression ( )

Return the current image compression settings.

Definition at line 1515 of file fits.cc.

1515 {
1516 auto fits = reinterpret_cast<fitsfile *>(fptr);
1517 int compType = 0; // cfitsio compression type
1518 fits_get_compression_type(fits, &compType, &status);
1519 if (behavior & AUTO_CHECK) {
1520 LSST_FITS_CHECK_STATUS(*this, "Getting compression type");
1521 }
1522
1523 ImageCompressionOptions::Tiles tiles = ndarray::allocate(MAX_COMPRESS_DIM);
1524 fits_get_tile_dim(fits, tiles.getNumElements(), tiles.getData(), &status);
1525 if (behavior & AUTO_CHECK) {
1526 LSST_FITS_CHECK_STATUS(*this, "Getting tile dimensions");
1527 }
1528
1529 float quantizeLevel;
1530 fits_get_quantize_level(fits, &quantizeLevel, &status);
1531 if (behavior & AUTO_CHECK) {
1532 LSST_FITS_CHECK_STATUS(*this, "Getting quantizeLevel");
1533 }
1534
1535 return ImageCompressionOptions(compressionAlgorithmFromCfitsio(compType), tiles, quantizeLevel);
1536}
ImageCompressionOptions::CompressionAlgorithm compressionAlgorithmFromCfitsio(int cfitsio)
Convert compression algorithm from cfitsio to ImageCompressionOptions::CompressionAlgorithm.

◆ getImageDim()

int lsst::afw::fits::Fits::getImageDim ( )

Return the number of dimensions in the current HDU.

Definition at line 1442 of file fits.cc.

1442 {
1443 int nAxis = 0;
1444 fits_get_img_dim(reinterpret_cast<fitsfile *>(fptr), &nAxis, &status);
1445 if (behavior & AUTO_CHECK) LSST_FITS_CHECK_STATUS(*this, "Getting NAXIS");
1446 return nAxis;
1447}

◆ getImageDType()

std::string lsst::afw::fits::Fits::getImageDType ( )

Return the numpy dtype equivalent of the image pixel type (e.g.

"uint16", "float64").

Definition at line 1486 of file fits.cc.

1486 {
1487 int bitpix = 0;
1488 fits_get_img_equivtype(reinterpret_cast<fitsfile *>(fptr), &bitpix, &status);
1489 if (behavior & AUTO_CHECK) LSST_FITS_CHECK_STATUS(*this, "Getting image type");
1490 // FITS' 'BITPIX' key is the number of bits in a pixel, but negative for
1491 // floats. But the above CFITSIO routine adds support for unsigned
1492 // integers by checking BZERO for an offset as well. So the 'bitpix' value
1493 // we get back from that should be the raw value for signed integers and
1494 // floats, but may be something else (still positive) for unsigned, and
1495 // hence we'll compare to some FITSIO constants to be safe looking at
1496 // integers.
1497 if (bitpix < 0) {
1498 return "float" + std::to_string(-bitpix);
1499 }
1500 switch (bitpix) {
1501 case BYTE_IMG: return "uint8";
1502 case SBYTE_IMG: return "int8";
1503 case SHORT_IMG: return "int16";
1504 case USHORT_IMG: return "uint16";
1505 case LONG_IMG: return "int32";
1506 case ULONG_IMG: return "uint32";
1507 case LONGLONG_IMG: return "int64";
1508 }
1509 throw LSST_EXCEPT(
1510 FitsError,
1511 (boost::format("Unrecognized BITPIX value: %d") % bitpix).str()
1512 );
1513}
T to_string(T... args)

◆ getImageShape()

template<int N>
ndarray::Vector< ndarray::Size, N > lsst::afw::fits::Fits::getImageShape ( )
inline

Return the shape of the current (image) HDU.

The order of dimensions is reversed from the FITS ordering, reflecting the usual (y,x) ndarray convention.

The template parameter must match the actual number of dimension in the image.

Definition at line 534 of file fits.h.

534 {
535 ndarray::Vector<long, N> nAxes(1);
536 getImageShapeImpl(N, nAxes.elems);
537 ndarray::Vector<ndarray::Size, N> shape;
538 for (int i = 0; i < N; ++i) shape[i] = nAxes[N - i - 1];
539 return shape;
540 }

◆ getTableArraySize() [1/2]

long lsst::afw::fits::Fits::getTableArraySize ( int col)

Return the size of an array column.

Definition at line 1236 of file fits.cc.

1236 {
1237 int typecode = 0;
1238 long result = 0;
1239 long width = 0;
1240 fits_get_coltype(reinterpret_cast<fitsfile *>(fptr), col + 1, &typecode, &result, &width, &status);
1241 if (behavior & AUTO_CHECK) {
1242 LSST_FITS_CHECK_STATUS(*this, boost::format("Looking up array size for column %d") % col);
1243 }
1244 return result;
1245}
py::object result
Definition _schema.cc:429
int col
Definition CR.cc:144

◆ getTableArraySize() [2/2]

long lsst::afw::fits::Fits::getTableArraySize ( std::size_t row,
int col )

Return the size of an variable-length array field.

Definition at line 1247 of file fits.cc.

1247 {
1248 long result = 0;
1249 long offset = 0;
1250 fits_read_descript(reinterpret_cast<fitsfile *>(fptr), col + 1, row + 1, &result, &offset, &status);
1251 if (behavior & AUTO_CHECK) {
1252 LSST_FITS_CHECK_STATUS(*this, boost::format("Looking up array size for cell (%d, %d)") % row % col);
1253 }
1254 return result;
1255}
int row
Definition CR.cc:145

◆ operator=() [1/2]

Fits & lsst::afw::fits::Fits::operator= ( const Fits & )
delete

◆ operator=() [2/2]

Fits & lsst::afw::fits::Fits::operator= ( Fits && )
delete

◆ readImage()

template<typename T , int N>
void lsst::afw::fits::Fits::readImage ( ndarray::Array< T, N, N > const & array,
ndarray::Vector< int, N > const & offset )
inline

Read an array from a FITS image.

Parameters
[out]arrayArray to be filled. Must already be allocated to the desired shape.
[in]offsetIndices of the first pixel to be read from the image.

Definition at line 563 of file fits.h.

563 {
564 ndarray::Vector<long, N> begin(offset.reverse());
565 ndarray::Vector<long, N> end(begin);
566 end += array.getShape().reverse();
567 ndarray::Vector<long, N> increment(1);
568 begin += increment; // first FITS pixel is 1, not 0
569 readImageImpl(N, array.getData(), begin.elems, end.elems, increment.elems);
570 }
int end
T begin(T... args)

◆ readKey()

template<typename T >
void lsst::afw::fits::Fits::readKey ( std::string const & key,
T & value )

Read a FITS header key into the given reference.

Definition at line 793 of file fits.cc.

793 {
794 readKeyImpl(*this, key.c_str(), value);
795 if (behavior & AUTO_CHECK) {
796 LSST_FITS_CHECK_STATUS(*this, boost::format("Reading key '%s'") % key);
797 }
798}

◆ readMetadata()

void lsst::afw::fits::Fits::readMetadata ( daf::base::PropertySet & metadata,
bool strip = false )

Read a FITS header into a PropertySet or PropertyList.

Parameters
[in,out]metadataA PropertySet or PropertyList that FITS header items will be added to.
[in]stripIf true, common FITS keys that usually have non-metadata intepretations (e.g. NAXIS, BITPIX) will be ignored.

Order will preserved if and only if the metadata object is actually a PropertyList.

Definition at line 1106 of file fits.cc.

1106 {
1107 MetadataIterationFunctor f;
1108 f.strip = strip;
1109 f.set = &metadata;
1110 f.list = dynamic_cast<daf::base::PropertyList *>(&metadata);
1111 forEachKey(f);
1112}
void forEachKey(HeaderIterationFunctor &functor)
Call a polymorphic functor for every key in the header.
Definition fits.cc:800

◆ readTableArray()

template<typename T >
void lsst::afw::fits::Fits::readTableArray ( std::size_t row,
int col,
int nElements,
T * value )

Read an array value from a binary table.

Definition at line 1211 of file fits.cc.

1211 {
1212 int anynul = false;
1213 fits_read_col(reinterpret_cast<fitsfile *>(fptr), FitsTableType<T>::CONSTANT, col + 1, row + 1, 1,
1214 nElements, nullptr, value, &anynul, &status);
1215 if (behavior & AUTO_CHECK) {
1216 LSST_FITS_CHECK_STATUS(*this, boost::format("Reading value at table cell (%d, %d)") % row % col);
1217 }
1218}

◆ readTableScalar() [1/2]

void lsst::afw::fits::Fits::readTableScalar ( std::size_t row,
int col,
std::string & value,
bool isVariableLength )

Read a string from a binary table.

Definition at line 1220 of file fits.cc.

1220 {
1221 int anynul = false;
1222 long size = isVariableLength ? getTableArraySize(row, col) : getTableArraySize(col);
1223 // We can't directly write into a std::string until C++17.
1224 std::vector<char> buf(size + 1, 0);
1225 // cfitsio wants a char** because they imagine we might want an array of strings,
1226 // but we only want one element.
1227 char *tmp = &buf.front();
1228 fits_read_col(reinterpret_cast<fitsfile *>(fptr), TSTRING, col + 1, row + 1, 1, 1, nullptr, &tmp, &anynul,
1229 &status);
1230 if (behavior & AUTO_CHECK) {
1231 LSST_FITS_CHECK_STATUS(*this, boost::format("Reading value at table cell (%d, %d)") % row % col);
1232 }
1233 value = std::string(tmp);
1234}
long getTableArraySize(int col)
Return the size of an array column.
Definition fits.cc:1236

◆ readTableScalar() [2/2]

template<typename T >
void lsst::afw::fits::Fits::readTableScalar ( std::size_t row,
int col,
T & value )
inline

Read an array scalar from a binary table.

Definition at line 617 of file fits.h.

617 {
618 readTableArray(row, col, 1, &value);
619 }
void readTableArray(std::size_t row, int col, int nElements, T *value)
Read an array value from a binary table.
Definition fits.cc:1211

◆ setHdu() [1/2]

void lsst::afw::fits::Fits::setHdu ( int hdu,
bool relative = false )

Set the current HDU.

Parameters
[in]hduThe HDU to move to (0-indexed; 0 is the Primary HDU). The special value of DEFAULT_HDU moves to the first extension if the Primary HDU is empty (has NAXIS==0) and the the Primary HDU is the current one.
[in]relativeIf true, move relative to the current HDU.

Definition at line 524 of file fits.cc.

524 {
525 if (relative) {
526 fits_movrel_hdu(reinterpret_cast<fitsfile *>(fptr), hdu, nullptr, &status);
527 if (behavior & AUTO_CHECK) {
528 LSST_FITS_CHECK_STATUS(*this, boost::format("Incrementing HDU by %d") % hdu);
529 }
530 } else {
531 if (hdu != DEFAULT_HDU) {
532 fits_movabs_hdu(reinterpret_cast<fitsfile *>(fptr), hdu + 1, nullptr, &status);
533 }
534 if (hdu == DEFAULT_HDU && getHdu() == 0 && getImageDim() == 0) {
535 // want a silent failure here
536 int tmpStatus = status;
537 fits_movrel_hdu(reinterpret_cast<fitsfile *>(fptr), 1, nullptr, &tmpStatus);
538 }
539 if (behavior & AUTO_CHECK) {
540 LSST_FITS_CHECK_STATUS(*this, boost::format("Moving to HDU %d") % hdu);
541 }
542 }
543}
int getImageDim()
Return the number of dimensions in the current HDU.
Definition fits.cc:1442
const int DEFAULT_HDU
Specify that the default HDU should be read.

◆ setHdu() [2/2]

void lsst::afw::fits::Fits::setHdu ( std::string const & name,
HduType hdutype = HduType::ANY,
int hduver = 0 )

Set the current HDU using its name, version and type.

Parameters
[in]nameThe name of the HDU to move to
[in]hdutypeThe type of HDU to match. If not supplied, defaults to ANY_HDU
[in]hduverThe value of EXTVER to match. If not supplied, defaults to 0

Definition at line 545 of file fits.cc.

545 {
546 fits_movnam_hdu(reinterpret_cast<fitsfile *>(fptr), static_cast<int>(hdutype),
547 const_cast<char *>(name.c_str()), hduver, &status);
548 if (behavior & AUTO_CHECK)
549 LSST_FITS_CHECK_STATUS(*this, boost::format("Moving to named HDU %s, type %d, hduver %d") % name %
550 static_cast<int>(hdutype) % hduver);
551}

◆ setImageCompression()

void lsst::afw::fits::Fits::setImageCompression ( ImageCompressionOptions const & options)

Set compression options for writing FITS images.

See also
ImageCompressionContext

Definition at line 1538 of file fits.cc.

1538 {
1539 auto fits = reinterpret_cast<fitsfile *>(fptr);
1540 fits_unset_compression_request(fits, &status); // wipe the slate and start over
1542 allowImageCompression ? comp.algorithm : ImageCompressionOptions::NONE;
1543 fits_set_compression_type(fits, compressionAlgorithmToCfitsio(algorithm), &status);
1544 if (behavior & AUTO_CHECK) {
1545 LSST_FITS_CHECK_STATUS(*this, "Setting compression type");
1546 }
1547
1548 if (algorithm == ImageCompressionOptions::NONE) {
1549 // Nothing else worth doing
1550 return;
1551 }
1552
1553 fits_set_tile_dim(fits, comp.tiles.getNumElements(), comp.tiles.getData(), &status);
1554 if (behavior & AUTO_CHECK) {
1555 LSST_FITS_CHECK_STATUS(*this, "Setting tile dimensions");
1556 }
1557
1558 if (comp.algorithm != ImageCompressionOptions::PLIO && std::isfinite(comp.quantizeLevel)) {
1559 fits_set_quantize_level(fits, comp.quantizeLevel, &status);
1560 if (behavior & AUTO_CHECK) {
1561 LSST_FITS_CHECK_STATUS(*this, "Setting quantization level");
1562 }
1563 }
1564}
T isfinite(T... args)
int compressionAlgorithmToCfitsio(ImageCompressionOptions::CompressionAlgorithm algorithm)
Convert ImageCompressionOptions::CompressionAlgorithm to cfitsio.

◆ updateColumnKey() [1/4]

void lsst::afw::fits::Fits::updateColumnKey ( std::string const & prefix,
int n,
char const * value )
inline

Definition at line 391 of file fits.h.

391 {
393 }
std::string prefix

◆ updateColumnKey() [2/4]

void lsst::afw::fits::Fits::updateColumnKey ( std::string const & prefix,
int n,
char const * value,
std::string const & comment )
inline

Definition at line 386 of file fits.h.

386 {
387 updateColumnKey(prefix, n, std::string(value), comment);
388 }

◆ updateColumnKey() [3/4]

template<typename T >
void lsst::afw::fits::Fits::updateColumnKey ( std::string const & prefix,
int n,
T const & value )

Definition at line 726 of file fits.cc.

726 {
727 updateKey((boost::format("%s%d") % prefix % (n + 1)).str(), value);
728 if (behavior & AUTO_CHECK) {
729 LSST_FITS_CHECK_STATUS(*this, boost::format("Updating key '%s%d': '%s'") % prefix % (n + 1) % value);
730 }
731}
void updateKey(std::string const &key, T const &value, std::string const &comment)
Set a FITS header key, editing if it already exists and appending it if not.
Definition fits.cc:678

◆ updateColumnKey() [4/4]

template<typename T >
void lsst::afw::fits::Fits::updateColumnKey ( std::string const & prefix,
int n,
T const & value,
std::string const & comment )

Update a key of the form XXXXXnnn, where XXXXX is the prefix and nnn is a column number.

Definition at line 710 of file fits.cc.

710 {
711 updateKey((boost::format("%s%d") % prefix % (n + 1)).str(), value, comment);
712 if (behavior & AUTO_CHECK) {
713 LSST_FITS_CHECK_STATUS(*this, boost::format("Updating key '%s%d': '%s'") % prefix % (n + 1) % value);
714 }
715}

◆ updateKey() [1/4]

void lsst::afw::fits::Fits::updateKey ( std::string const & key,
char const * value )
inline

Definition at line 361 of file fits.h.

361{ updateKey(key, std::string(value)); }

◆ updateKey() [2/4]

void lsst::afw::fits::Fits::updateKey ( std::string const & key,
char const * value,
std::string const & comment )
inline

Definition at line 356 of file fits.h.

356 {
357 updateKey(key, std::string(value), comment);
358 }

◆ updateKey() [3/4]

template<typename T >
void lsst::afw::fits::Fits::updateKey ( std::string const & key,
T const & value )

Definition at line 694 of file fits.cc.

694 {
695 updateKeyImpl(*this, key.c_str(), value, nullptr);
696 if (behavior & AUTO_CHECK) {
697 LSST_FITS_CHECK_STATUS(*this, boost::format("Updating key '%s': '%s'") % key % value);
698 }
699}

◆ updateKey() [4/4]

template<typename T >
void lsst::afw::fits::Fits::updateKey ( std::string const & key,
T const & value,
std::string const & comment )

Set a FITS header key, editing if it already exists and appending it if not.

Definition at line 678 of file fits.cc.

678 {
679 updateKeyImpl(*this, key.c_str(), value, comment.c_str());
680 if (behavior & AUTO_CHECK) {
681 LSST_FITS_CHECK_STATUS(*this, boost::format("Updating key '%s': '%s'") % key % value);
682 }
683}

◆ writeColumnKey() [1/4]

void lsst::afw::fits::Fits::writeColumnKey ( std::string const & prefix,
int n,
char const * value )
inline

Definition at line 405 of file fits.h.

405 {
407 }
void writeColumnKey(std::string const &prefix, int n, T const &value, std::string const &comment)
Write a key of the form XXXXXnnn, where XXXXX is the prefix and nnn is a column number.
Definition fits.cc:718

◆ writeColumnKey() [2/4]

void lsst::afw::fits::Fits::writeColumnKey ( std::string const & prefix,
int n,
char const * value,
std::string const & comment )
inline

Definition at line 400 of file fits.h.

400 {
401 writeColumnKey(prefix, n, std::string(value), comment);
402 }

◆ writeColumnKey() [3/4]

template<typename T >
void lsst::afw::fits::Fits::writeColumnKey ( std::string const & prefix,
int n,
T const & value )

Definition at line 734 of file fits.cc.

734 {
735 writeKey((boost::format("%s%d") % prefix % (n + 1)).str(), value);
736 if (behavior & AUTO_CHECK) {
737 LSST_FITS_CHECK_STATUS(*this, boost::format("Writing key '%s%d': '%s'") % prefix % (n + 1) % value);
738 }
739}
void writeKey(std::string const &key, T const &value, std::string const &comment)
Add a FITS header key to the bottom of the header.
Definition fits.cc:686

◆ writeColumnKey() [4/4]

template<typename T >
void lsst::afw::fits::Fits::writeColumnKey ( std::string const & prefix,
int n,
T const & value,
std::string const & comment )

Write a key of the form XXXXXnnn, where XXXXX is the prefix and nnn is a column number.

Definition at line 718 of file fits.cc.

718 {
719 writeKey((boost::format("%s%d") % prefix % (n + 1)).str(), value, comment);
720 if (behavior & AUTO_CHECK) {
721 LSST_FITS_CHECK_STATUS(*this, boost::format("Writing key '%s%d': '%s'") % prefix % (n + 1) % value);
722 }
723}

◆ writeImage() [1/2]

template<typename T >
void lsst::afw::fits::Fits::writeImage ( image::ImageBase< T > const & image,
ImageWriteOptions const & options,
daf::base::PropertySet const * header = nullptr,
image::Mask< image::MaskPixel > const * mask = nullptr )

Write an image to FITS.

This method is all-inclusive, and covers creating the HDU (with the correct BITPIX), writing the header and optional scaling and compression of the image.

Parameters
[in]imageImage to write to FITS.
[in]optionsOptions controlling the write (scaling, compression).
[in]headerFITS header to write.
[in]maskMask for image (used for statistics when scaling).

Definition at line 1315 of file fits.cc.

1317 {
1318 auto fits = reinterpret_cast<fitsfile *>(fptr);
1319 ImageCompressionOptions const &compression =
1320 image.getBBox().getArea() > 0
1321 ? options.compression
1322 : ImageCompressionOptions(
1323 ImageCompressionOptions::NONE); // cfitsio can't compress empty images
1324 ImageCompressionContext comp(*this, compression); // RAII
1325 if (behavior & AUTO_CHECK) {
1326 LSST_FITS_CHECK_STATUS(*this, "Activating compression for write image");
1327 }
1328
1329 ImageScale scale = options.scaling.determine(image, mask);
1330
1331 // We need a place to put the image+header, and CFITSIO needs to know the dimenions.
1332 ndarray::Vector<long, 2> dims(image.getArray().getShape().reverse());
1333 createImageImpl(scale.bitpix == 0 ? detail::Bitpix<T>::value : scale.bitpix, 2, dims.elems);
1334
1335 // Write the header
1337 geom::createTrivialWcsMetadata(image::detail::wcsNameForXY0, image.getXY0());
1339 if (header) {
1340 fullMetadata = header->deepCopy();
1341 fullMetadata->combine(*wcsMetadata);
1342 } else {
1343 fullMetadata = wcsMetadata;
1344 }
1345 writeMetadata(*fullMetadata);
1346
1347 // Scale the image how we want it on disk
1348 ndarray::Array<T const, 2, 2> array = makeContiguousArray(image.getArray());
1349 auto pixels = scale.toFits(array, compression.quantizeLevel != 0, options.scaling.fuzz,
1350 options.compression.tiles, options.scaling.seed);
1351
1352 // We only want cfitsio to do the scale and zero for unsigned 64-bit integer types. For those,
1353 // "double bzero" has sufficient precision to represent the appropriate value. We'll let
1354 // cfitsio handle it itself.
1355 // In all other cases, we will convert the image to use the appropriate scale and zero
1356 // (because we want to fuzz the numbers in the quantisation), so we don't want cfitsio
1357 // rescaling.
1359 fits_set_bscale(fits, 1.0, 0.0, &status);
1360 if (behavior & AUTO_CHECK) {
1361 LSST_FITS_CHECK_STATUS(*this, "Setting bscale,bzero");
1362 }
1363 }
1364
1365 // Write the pixels
1366 int const fitsType = scale.bitpix == 0 ? FitsType<T>::CONSTANT : fitsTypeForBitpix(scale.bitpix);
1367 fits_write_img(fits, fitsType, 1, pixels->getNumElements(), const_cast<void *>(pixels->getData()),
1368 &status);
1369 if (behavior & AUTO_CHECK) {
1370 LSST_FITS_CHECK_STATUS(*this, "Writing image");
1371 }
1372
1373 // Now write the headers we didn't want cfitsio to know about when we were writing the pixels
1374 // (because we don't want it using them to modify the pixels, and we don't want it overwriting
1375 // these values).
1377 std::isfinite(scale.bzero) && std::isfinite(scale.bscale) && (scale.bscale != 0.0)) {
1379 if (scale.bzero != 0.0) {
1380 fits_write_key_lng(fits, "BZERO", static_cast<long>(scale.bzero),
1381 "Scaling: MEMORY = BZERO + BSCALE * DISK", &status);
1382 }
1383 if (scale.bscale != 1.0) {
1384 fits_write_key_lng(fits, "BSCALE", static_cast<long>(scale.bscale),
1385 "Scaling: MEMORY = BZERO + BSCALE * DISK", &status);
1386 }
1387 } else {
1388 fits_write_key_dbl(fits, "BZERO", scale.bzero, 12, "Scaling: MEMORY = BZERO + BSCALE * DISK",
1389 &status);
1390 fits_write_key_dbl(fits, "BSCALE", scale.bscale, 12, "Scaling: MEMORY = BZERO + BSCALE * DISK",
1391 &status);
1392 }
1393 if (behavior & AUTO_CHECK) {
1394 LSST_FITS_CHECK_STATUS(*this, "Writing BSCALE,BZERO");
1395 }
1396 }
1397
1398 if (scale.bitpix > 0 && !std::numeric_limits<T>::is_integer) {
1399 fits_write_key_lng(fits, "BLANK", scale.blank, "Value for undefined pixels", &status);
1400 fits_write_key_lng(fits, "ZDITHER0", options.scaling.seed, "Dithering seed", &status);
1401 fits_write_key_str(fits, "ZQUANTIZ", "SUBTRACTIVE_DITHER_1", "Dithering algorithm", &status);
1402 if (behavior & AUTO_CHECK) {
1403 LSST_FITS_CHECK_STATUS(*this, "Writing [Z]BLANK");
1404 }
1405 }
1406
1407 // cfitsio says this is deprecated, but Pan-STARRS found that it was sometimes necessary, writing:
1408 // "This forces a re-scan of the header to ensure everything's kosher.
1409 // Without this, compressed HDUs have been written out with PCOUNT=0 and TFORM1 not correctly set."
1410 fits_set_hdustruc(fits, &status);
1411 if (behavior & AUTO_CHECK) {
1412 LSST_FITS_CHECK_STATUS(*this, "Finalizing header");
1413 }
1414}
afw::table::Key< afw::table::Array< MaskPixelT > > mask
void writeMetadata(daf::base::PropertySet const &metadata)
Read a FITS header into a PropertySet or PropertyList.
Definition fits.cc:1114
scale(algorithm, min, max=None, frame=None)
Definition ds9.py:108
ndarray::Array< T const, N, N > const makeContiguousArray(ndarray::Array< T, N, C > const &array)
Construct a contiguous ndarray.
Definition fits.h:212
std::string const wcsNameForXY0
Definition ImageBase.h:70

◆ writeImage() [2/2]

template<typename T , int N, int C>
void lsst::afw::fits::Fits::writeImage ( ndarray::Array< T const, N, C > const & array)
inline

Write an ndarray::Array to a FITS image HDU.

The HDU must already exist and have the correct bitpix.

An extra deep-copy may be necessary if the array is not fully contiguous.

No compression or scaling is performed.

Definition at line 498 of file fits.h.

498 {
499 writeImageImpl(makeContiguousArray(array).getData(), array.getNumElements());
500 }

◆ writeKey() [1/4]

void lsst::afw::fits::Fits::writeKey ( std::string const & key,
char const * value )
inline

Definition at line 379 of file fits.h.

379{ writeKey(key, std::string(value)); }

◆ writeKey() [2/4]

void lsst::afw::fits::Fits::writeKey ( std::string const & key,
char const * value,
std::string const & comment )
inline

Definition at line 374 of file fits.h.

374 {
375 writeKey(key, std::string(value), comment);
376 }

◆ writeKey() [3/4]

template<typename T >
void lsst::afw::fits::Fits::writeKey ( std::string const & key,
T const & value )

Definition at line 702 of file fits.cc.

702 {
703 writeKeyImpl(*this, key.c_str(), value, nullptr);
704 if (behavior & AUTO_CHECK) {
705 LSST_FITS_CHECK_STATUS(*this, boost::format("Writing key '%s': '%s'") % key % value);
706 }
707}

◆ writeKey() [4/4]

template<typename T >
void lsst::afw::fits::Fits::writeKey ( std::string const & key,
T const & value,
std::string const & comment )

Add a FITS header key to the bottom of the header.

If the key is HISTORY or COMMENT and the value is a std::string or C-string, a special HISTORY or COMMENT key will be appended (and the comment argument will be ignored if present).

Definition at line 686 of file fits.cc.

686 {
687 writeKeyImpl(*this, key.c_str(), value, comment.c_str());
688 if (behavior & AUTO_CHECK) {
689 LSST_FITS_CHECK_STATUS(*this, boost::format("Writing key '%s': '%s'") % key % value);
690 }
691}

◆ writeMetadata()

void lsst::afw::fits::Fits::writeMetadata ( daf::base::PropertySet const & metadata)

Read a FITS header into a PropertySet or PropertyList.

Parameters
[in]metadataA PropertySet or PropertyList whose items will be appended to the FITS header.

All keys will be appended to the FITS header rather than used to update existing keys. Order of keys will be preserved if and only if the metadata object is actually a PropertyList.

Definition at line 1114 of file fits.cc.

1114 {
1115 using NameList = std::vector<std::string>;
1116 daf::base::PropertyList const *pl = dynamic_cast<daf::base::PropertyList const *>(&metadata);
1117 NameList paramNames;
1118 if (pl) {
1119 paramNames = pl->getOrderedNames();
1120 } else {
1121 paramNames = metadata.paramNames(false);
1122 }
1123 for (auto const &paramName : paramNames) {
1124 if (!isKeyIgnored(paramName, true)) {
1125 if (pl) {
1126 writeKeyFromProperty(*this, metadata, paramName, pl->getComment(paramName).c_str());
1127 } else {
1128 writeKeyFromProperty(*this, metadata, paramName);
1129 }
1130 }
1131 }
1132}

◆ writeTableArray()

template<typename T >
void lsst::afw::fits::Fits::writeTableArray ( std::size_t row,
int col,
int nElements,
T const * value )

Write an array value to a binary table.

Definition at line 1188 of file fits.cc.

1188 {
1189 fits_write_col(reinterpret_cast<fitsfile *>(fptr), FitsTableType<T>::CONSTANT, col + 1, row + 1, 1,
1190 nElements, const_cast<T *>(value), &status);
1191 if (behavior & AUTO_CHECK) {
1192 LSST_FITS_CHECK_STATUS(*this, boost::format("Writing %d-element array at table cell (%d, %d)") %
1193 nElements % row % col);
1194 }
1195}

◆ writeTableScalar() [1/2]

void lsst::afw::fits::Fits::writeTableScalar ( std::size_t row,
int col,
std::string const & value )

Write a string to a binary table.

Definition at line 1197 of file fits.cc.

1197 {
1198 // cfitsio doesn't let us specify the size of a string, it just looks for null terminator.
1199 // Using std::string::c_str() guarantees that we have one. But we can't store arbitrary
1200 // data in a string field because cfitsio will also chop off anything after the first null
1201 // terminator.
1202 char const *tmp = value.c_str();
1203 fits_write_col(reinterpret_cast<fitsfile *>(fptr), TSTRING, col + 1, row + 1, 1, 1,
1204 const_cast<char const **>(&tmp), &status);
1205 if (behavior & AUTO_CHECK) {
1206 LSST_FITS_CHECK_STATUS(*this, boost::format("Writing value at table cell (%d, %d)") % row % col);
1207 }
1208}

◆ writeTableScalar() [2/2]

template<typename T >
void lsst::afw::fits::Fits::writeTableScalar ( std::size_t row,
int col,
T value )
inline

Write a scalar value to a binary table.

Definition at line 605 of file fits.h.

605 {
606 writeTableArray(row, col, 1, &value);
607 }
void writeTableArray(std::size_t row, int col, int nElements, T const *value)
Write an array value to a binary table.
Definition fits.cc:1188

Member Data Documentation

◆ behavior

int lsst::afw::fits::Fits::behavior

Definition at line 673 of file fits.h.

◆ fptr

void* lsst::afw::fits::Fits::fptr

Definition at line 671 of file fits.h.

◆ status

int lsst::afw::fits::Fits::status

Definition at line 672 of file fits.h.


The documentation for this class was generated from the following files: