LSST Applications g0f08755f38+9c285cab97,g1635faa6d4+13f3999e92,g1653933729+a8ce1bb630,g1a0ca8cf93+bf6eb00ceb,g28da252d5a+0829b12dee,g29321ee8c0+5700dc9eac,g2bbee38e9b+9634bc57db,g2bc492864f+9634bc57db,g2cdde0e794+c2c89b37c4,g3156d2b45e+41e33cbcdc,g347aa1857d+9634bc57db,g35bb328faa+a8ce1bb630,g3a166c0a6a+9634bc57db,g3e281a1b8c+9f2c4e2fc3,g414038480c+077ccc18e7,g41af890bb2+fde0dd39b6,g5fbc88fb19+17cd334064,g781aacb6e4+a8ce1bb630,g80478fca09+55a9465950,g82479be7b0+d730eedb7d,g858d7b2824+9c285cab97,g9125e01d80+a8ce1bb630,g9726552aa6+10f999ec6a,ga5288a1d22+2a84bb7594,gacf8899fa4+c69c5206e8,gae0086650b+a8ce1bb630,gb58c049af0+d64f4d3760,gc28159a63d+9634bc57db,gcf0d15dbbd+4b7d09cae4,gda3e153d99+9c285cab97,gda6a2b7d83+4b7d09cae4,gdaeeff99f8+1711a396fd,ge2409df99d+5e831397f4,ge79ae78c31+9634bc57db,gf0baf85859+147a0692ba,gf3967379c6+41c94011de,gf3fb38a9a8+8f07a9901b,gfb92a5be7c+9c285cab97,w.2024.46
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 1579 of file fits.cc.

1580 : fptr(nullptr), status(0), behavior(behavior_) {
1581 if (mode == "r" || mode == "rb") {
1582 fits_open_file(reinterpret_cast<fitsfile **>(&fptr), const_cast<char *>(filename.c_str()), READONLY,
1583 &status);
1584 } else if (mode == "w" || mode == "wb") {
1585 std::filesystem::remove(filename); // cfitsio doesn't like over-writing files
1586 fits_create_file(reinterpret_cast<fitsfile **>(&fptr), const_cast<char *>(filename.c_str()), &status);
1587 } else if (mode == "a" || mode == "ab") {
1588 fits_open_file(reinterpret_cast<fitsfile **>(&fptr), const_cast<char *>(filename.c_str()), READWRITE,
1589 &status);
1590 int nHdu = 0;
1591 fits_get_num_hdus(reinterpret_cast<fitsfile *>(fptr), &nHdu, &status);
1592 fits_movabs_hdu(reinterpret_cast<fitsfile *>(fptr), nHdu, nullptr, &status);
1593 if ((behavior & AUTO_CHECK) && (behavior & AUTO_CLOSE) && (status) && (fptr)) {
1594 // We're about to throw an exception, and the destructor won't get called
1595 // because we're in the constructor, so cleanup here first.
1596 int tmpStatus = 0;
1597 fits_close_file(reinterpret_cast<fitsfile *>(fptr), &tmpStatus);
1598 }
1599 } else {
1600 throw LSST_EXCEPT(
1601 FitsError,
1602 (boost::format("Invalid mode '%s' given when opening file '%s'") % mode % filename).str());
1603 }
1604 if (behavior & AUTO_CHECK) {
1605 LSST_FITS_CHECK_STATUS(*this, boost::format("Opening file '%s' with mode '%s'") % filename % mode);
1606 }
1607}
#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 1609 of file fits.cc.

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

◆ 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 1153 of file fits.cc.

1153 {
1154 int nCols = 0;
1155 fits_get_num_cols(reinterpret_cast<fitsfile *>(fptr), &nCols, &status);
1156 std::string tform = makeColumnFormat<T>(size);
1157 fits_insert_col(reinterpret_cast<fitsfile *>(fptr), nCols + 1, const_cast<char *>(ttype.c_str()),
1158 const_cast<char *>(tform.c_str()), &status);
1159 if (behavior & AUTO_CHECK) {
1160 LSST_FITS_CHECK_STATUS(*this, boost::format("Adding column '%s' with size %d") % ttype % size);
1161 }
1162 return nCols;
1163}
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 1166 of file fits.cc.

1166 {
1167 int nCols = addColumn<T>(ttype, size);
1168 updateColumnKey("TTYPE", nCols, ttype, comment);
1169 if (behavior & AUTO_CHECK) {
1170 LSST_FITS_CHECK_STATUS(*this, boost::format("Adding column '%s' with size %d") % ttype % size);
1171 }
1172 return nCols;
1173}
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 1175 of file fits.cc.

1175 {
1176 long first = 0;
1177 fits_get_num_rows(reinterpret_cast<fitsfile *>(fptr), &first, &status);
1178 fits_insert_rows(reinterpret_cast<fitsfile *>(fptr), first, nRows, &status);
1179 if (behavior & AUTO_CHECK) {
1180 LSST_FITS_CHECK_STATUS(*this, boost::format("Adding %d rows to binary table") % nRows);
1181 }
1182 return first;
1183}

◆ 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 1774 of file fits.cc.

1774 {
1775 auto fits = reinterpret_cast<fitsfile *>(fptr);
1776 if (getHdu() != 0 || countHdus() == 1) {
1777 return false; // Can't possibly be the PHU leading a compressed image
1778 }
1779 // Check NAXIS = 0
1780 int naxis;
1781 fits_get_img_dim(fits, &naxis, &status);
1782 if (behavior & AUTO_CHECK) {
1783 LSST_FITS_CHECK_STATUS(*this, "Checking NAXIS of PHU");
1784 }
1785 if (naxis != 0) {
1786 return false;
1787 }
1788 // Check first extension (and move back there when we're done if we're not compressed)
1789 HduMoveGuard move(*this, 1);
1790 bool isCompressed = fits_is_compressed_image(fits, &status);
1791 if (behavior & AUTO_CHECK) {
1792 LSST_FITS_CHECK_STATUS(*this, "Checking compression");
1793 }
1794 if (isCompressed) {
1795 move.disable();
1796 }
1797 return isCompressed;
1798}
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 1462 of file fits.cc.

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

◆ closeFile()

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

Close a FITS file.

Definition at line 1650 of file fits.cc.

1650 {
1651 fits_close_file(reinterpret_cast<fitsfile *>(fptr), &status);
1652 fptr = nullptr;
1653}

◆ 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 1185 of file fits.cc.

1185 {
1186 long r = 0;
1187 fits_get_num_rows(reinterpret_cast<fitsfile *>(fptr), &r, &status);
1188 if (behavior & AUTO_CHECK) {
1189 LSST_FITS_CHECK_STATUS(*this, "Checking how many rows are in table");
1190 }
1191 return r;
1192}

◆ 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 1266 of file fits.cc.

1266 {
1267 long naxes = 0;
1268 fits_create_img(reinterpret_cast<fitsfile *>(fptr), 8, 0, &naxes, &status);
1269 if (behavior & AUTO_CHECK) {
1270 LSST_FITS_CHECK_STATUS(*this, "Creating empty image HDU");
1271 }
1272}

◆ 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 1143 of file fits.cc.

1143 {
1144 char *ttype = nullptr;
1145 char *tform = nullptr;
1146 fits_create_tbl(reinterpret_cast<fitsfile *>(fptr), BINARY_TBL, 0, 0, &ttype, &tform, nullptr, nullptr, &status);
1147 if (behavior & AUTO_CHECK) {
1148 LSST_FITS_CHECK_STATUS(*this, "Creating binary table");
1149 }
1150}

◆ 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 1522 of file fits.cc.

1522 {
1523 auto fits = reinterpret_cast<fitsfile *>(fptr);
1524 int compType = 0; // cfitsio compression type
1525 fits_get_compression_type(fits, &compType, &status);
1526 if (behavior & AUTO_CHECK) {
1527 LSST_FITS_CHECK_STATUS(*this, "Getting compression type");
1528 }
1529
1530 ImageCompressionOptions::Tiles tiles = ndarray::allocate(MAX_COMPRESS_DIM);
1531 fits_get_tile_dim(fits, tiles.getNumElements(), tiles.getData(), &status);
1532 if (behavior & AUTO_CHECK) {
1533 LSST_FITS_CHECK_STATUS(*this, "Getting tile dimensions");
1534 }
1535
1536 float quantizeLevel;
1537 fits_get_quantize_level(fits, &quantizeLevel, &status);
1538 if (behavior & AUTO_CHECK) {
1539 LSST_FITS_CHECK_STATUS(*this, "Getting quantizeLevel");
1540 }
1541
1542 return ImageCompressionOptions(compressionAlgorithmFromCfitsio(compType), tiles, quantizeLevel);
1543}
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 1449 of file fits.cc.

1449 {
1450 int nAxis = 0;
1451 fits_get_img_dim(reinterpret_cast<fitsfile *>(fptr), &nAxis, &status);
1452 if (behavior & AUTO_CHECK) LSST_FITS_CHECK_STATUS(*this, "Getting NAXIS");
1453 return nAxis;
1454}

◆ 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 1493 of file fits.cc.

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

1243 {
1244 int typecode = 0;
1245 long result = 0;
1246 long width = 0;
1247 fits_get_coltype(reinterpret_cast<fitsfile *>(fptr), col + 1, &typecode, &result, &width, &status);
1248 if (behavior & AUTO_CHECK) {
1249 LSST_FITS_CHECK_STATUS(*this, boost::format("Looking up array size for column %d") % col);
1250 }
1251 return result;
1252}
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 1254 of file fits.cc.

1254 {
1255 long result = 0;
1256 long offset = 0;
1257 fits_read_descript(reinterpret_cast<fitsfile *>(fptr), col + 1, row + 1, &result, &offset, &status);
1258 if (behavior & AUTO_CHECK) {
1259 LSST_FITS_CHECK_STATUS(*this, boost::format("Looking up array size for cell (%d, %d)") % row % col);
1260 }
1261 return result;
1262}
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 1113 of file fits.cc.

1113 {
1114 MetadataIterationFunctor f;
1115 f.strip = strip;
1116 f.set = &metadata;
1117 f.list = dynamic_cast<daf::base::PropertyList *>(&metadata);
1118 forEachKey(f);
1119}
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 1218 of file fits.cc.

1218 {
1219 int anynul = false;
1220 fits_read_col(reinterpret_cast<fitsfile *>(fptr), FitsTableType<T>::CONSTANT, col + 1, row + 1, 1,
1221 nElements, nullptr, value, &anynul, &status);
1222 if (behavior & AUTO_CHECK) {
1223 LSST_FITS_CHECK_STATUS(*this, boost::format("Reading value at table cell (%d, %d)") % row % col);
1224 }
1225}

◆ 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 1227 of file fits.cc.

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

◆ 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:1218

◆ 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:1449
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 1545 of file fits.cc.

1545 {
1546 auto fits = reinterpret_cast<fitsfile *>(fptr);
1547 fits_unset_compression_request(fits, &status); // wipe the slate and start over
1549 allowImageCompression ? comp.algorithm : ImageCompressionOptions::NONE;
1550 fits_set_compression_type(fits, compressionAlgorithmToCfitsio(algorithm), &status);
1551 if (behavior & AUTO_CHECK) {
1552 LSST_FITS_CHECK_STATUS(*this, "Setting compression type");
1553 }
1554
1555 if (algorithm == ImageCompressionOptions::NONE) {
1556 // Nothing else worth doing
1557 return;
1558 }
1559
1560 fits_set_tile_dim(fits, comp.tiles.getNumElements(), comp.tiles.getData(), &status);
1561 if (behavior & AUTO_CHECK) {
1562 LSST_FITS_CHECK_STATUS(*this, "Setting tile dimensions");
1563 }
1564
1565 if (comp.algorithm != ImageCompressionOptions::PLIO && std::isfinite(comp.quantizeLevel)) {
1566 fits_set_quantize_level(fits, comp.quantizeLevel, &status);
1567 if (behavior & AUTO_CHECK) {
1568 LSST_FITS_CHECK_STATUS(*this, "Setting quantization level");
1569 }
1570 }
1571}
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 1322 of file fits.cc.

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

1121 {
1122 using NameList = std::vector<std::string>;
1123 daf::base::PropertyList const *pl = dynamic_cast<daf::base::PropertyList const *>(&metadata);
1124 NameList paramNames;
1125 if (pl) {
1126 paramNames = pl->getOrderedNames();
1127 } else {
1128 paramNames = metadata.paramNames(false);
1129 }
1130 for (auto const &paramName : paramNames) {
1131 if (!isKeyIgnored(paramName, true)) {
1132 if (pl) {
1133 writeKeyFromProperty(*this, metadata, paramName, pl->getComment(paramName).c_str());
1134 } else {
1135 writeKeyFromProperty(*this, metadata, paramName);
1136 }
1137 }
1138 }
1139}

◆ 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 1195 of file fits.cc.

1195 {
1196 fits_write_col(reinterpret_cast<fitsfile *>(fptr), FitsTableType<T>::CONSTANT, col + 1, row + 1, 1,
1197 nElements, const_cast<T *>(value), &status);
1198 if (behavior & AUTO_CHECK) {
1199 LSST_FITS_CHECK_STATUS(*this, boost::format("Writing %d-element array at table cell (%d, %d)") %
1200 nElements % row % col);
1201 }
1202}

◆ 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 1204 of file fits.cc.

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

◆ 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:1195

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: