LSST Applications  21.0.0-172-gfb10e10a+18fedfabac,22.0.0+297cba6710,22.0.0+80564b0ff1,22.0.0+8d77f4f51a,22.0.0+a28f4c53b1,22.0.0+dcf3732eb2,22.0.1-1-g7d6de66+2a20fdde0d,22.0.1-1-g8e32f31+297cba6710,22.0.1-1-geca5380+7fa3b7d9b6,22.0.1-12-g44dc1dc+2a20fdde0d,22.0.1-15-g6a90155+515f58c32b,22.0.1-16-g9282f48+790f5f2caa,22.0.1-2-g92698f7+dcf3732eb2,22.0.1-2-ga9b0f51+7fa3b7d9b6,22.0.1-2-gd1925c9+bf4f0e694f,22.0.1-24-g1ad7a390+a9625a72a8,22.0.1-25-g5bf6245+3ad8ecd50b,22.0.1-25-gb120d7b+8b5510f75f,22.0.1-27-g97737f7+2a20fdde0d,22.0.1-32-gf62ce7b1+aa4237961e,22.0.1-4-g0b3f228+2a20fdde0d,22.0.1-4-g243d05b+871c1b8305,22.0.1-4-g3a563be+32dcf1063f,22.0.1-4-g44f2e3d+9e4ab0f4fa,22.0.1-42-gca6935d93+ba5e5ca3eb,22.0.1-5-g15c806e+85460ae5f3,22.0.1-5-g58711c4+611d128589,22.0.1-5-g75bb458+99c117b92f,22.0.1-6-g1c63a23+7fa3b7d9b6,22.0.1-6-g50866e6+84ff5a128b,22.0.1-6-g8d3140d+720564cf76,22.0.1-6-gd805d02+cc5644f571,22.0.1-8-ge5750ce+85460ae5f3,master-g6e05de7fdc+babf819c66,master-g99da0e417a+8d77f4f51a,w.2021.48
LSST Data Management Base Package
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. More...
 
int getHdu ()
 Return the current HDU (0-indexed; 0 is the Primary HDU). More...
 
void setHdu (int hdu, bool relative=false)
 Set the current HDU. More...
 
int countHdus ()
 Return the number of HDUs in the file. More...
 
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. More...
 
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. More...
 
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. More...
 
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. More...
 
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. More...
 
void readMetadata (daf::base::PropertySet &metadata, bool strip=false)
 Read a FITS header into a PropertySet or PropertyList. More...
 
template<typename T >
void readKey (std::string const &key, T &value)
 Read a FITS header key into the given reference. More...
 
void forEachKey (HeaderIterationFunctor &functor)
 Call a polymorphic functor for every key in the header. More...
 
void createEmpty ()
 Create an empty image HDU with NAXIS=0 at the end of the file. More...
 
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. More...
 
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. More...
 
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. More...
 
template<typename T >
void writeImage (image::ImageBase< T > const &image, ImageWriteOptions const &options, std::shared_ptr< daf::base::PropertySet const > header=std::shared_ptr< daf::base::PropertyList >(), std::shared_ptr< image::Mask< image::MaskPixel > const > mask=std::shared_ptr< image::Mask< image::MaskPixel >>())
 Write an image to FITS. More...
 
int getImageDim ()
 Return the number of dimensions in the current HDU. More...
 
template<int N>
ndarray::Vector< ndarray::Size, N > getImageShape ()
 Return the shape of the current (image) HDU. More...
 
template<typename T >
bool checkImageType ()
 Return true if the current HDU is compatible with the given pixel type. More...
 
std::string getImageDType ()
 Return the numpy dtype equivalent of the image pixel type (e.g. More...
 
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. More...
 
void createTable ()
 Create a new binary table extension. More...
 
template<typename T >
int addColumn (std::string const &ttype, int size, std::string const &comment)
 Add a column to a table. More...
 
template<typename T >
int addColumn (std::string const &ttype, int size)
 Add a column to a table. More...
 
std::size_t addRows (std::size_t nRows)
 Append rows to a table, and return the index of the first new row. More...
 
std::size_t countRows ()
 Return the number of row in a table. More...
 
template<typename T >
void writeTableArray (std::size_t row, int col, int nElements, T const *value)
 Write an array value to a binary table. More...
 
template<typename T >
void writeTableScalar (std::size_t row, int col, T value)
 Write a scalar value to a binary table. More...
 
void writeTableScalar (std::size_t row, int col, std::string const &value)
 Write a string to a binary table. More...
 
template<typename T >
void readTableArray (std::size_t row, int col, int nElements, T *value)
 Read an array value from a binary table. More...
 
template<typename T >
void readTableScalar (std::size_t row, int col, T &value)
 Read an array scalar from a binary table. More...
 
void readTableScalar (std::size_t row, int col, std::string &value, bool isVariableLength)
 Read a string from a binary table. More...
 
long getTableArraySize (int col)
 Return the size of an array column. More...
 
long getTableArraySize (std::size_t row, int col)
 Return the size of an variable-length array field. More...
 
 Fits ()
 Default constructor; set all data members to 0. More...
 
 Fits (std::string const &filename, std::string const &mode, int behavior)
 Open or create a FITS file from disk. More...
 
 Fits (MemFileManager &manager, std::string const &mode, int behavior)
 Open or create a FITS file from an in-memory file. More...
 
void closeFile ()
 Close a FITS file. More...
 
void setImageCompression (ImageCompressionOptions const &options)
 Set compression options for writing FITS images. More...
 
ImageCompressionOptions getImageCompression ()
 Return the current image compression settings. More...
 
bool checkCompressedImagePhu ()
 Go to the first image header in the FITS file. More...
 
 ~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 297 of file fits.h.

Member Enumeration Documentation

◆ BehaviorFlags

Enumerator
AUTO_CLOSE 
AUTO_CHECK 

Definition at line 306 of file fits.h.

306  {
307  AUTO_CLOSE = 0x01, // Close files when the Fits object goes out of scope if fptr != NULL
308  AUTO_CHECK = 0x02 // Call LSST_FITS_CHECK_STATUS after every cfitsio call
309  };

Constructor & Destructor Documentation

◆ Fits() [1/5]

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

Default constructor; set all data members to 0.

Definition at line 609 of file fits.h.

609 : 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 1552 of file fits.cc.

1553  : fptr(nullptr), status(0), behavior(behavior_) {
1554  if (mode == "r" || mode == "rb") {
1555  fits_open_file(reinterpret_cast<fitsfile **>(&fptr), const_cast<char *>(filename.c_str()), READONLY,
1556  &status);
1557  } else if (mode == "w" || mode == "wb") {
1558  std::filesystem::remove(filename); // cfitsio doesn't like over-writing files
1559  fits_create_file(reinterpret_cast<fitsfile **>(&fptr), const_cast<char *>(filename.c_str()), &status);
1560  } else if (mode == "a" || mode == "ab") {
1561  fits_open_file(reinterpret_cast<fitsfile **>(&fptr), const_cast<char *>(filename.c_str()), READWRITE,
1562  &status);
1563  int nHdu = 0;
1564  fits_get_num_hdus(reinterpret_cast<fitsfile *>(fptr), &nHdu, &status);
1565  fits_movabs_hdu(reinterpret_cast<fitsfile *>(fptr), nHdu, nullptr, &status);
1566  if ((behavior & AUTO_CHECK) && (behavior & AUTO_CLOSE) && (status) && (fptr)) {
1567  // We're about to throw an exception, and the destructor won't get called
1568  // because we're in the constructor, so cleanup here first.
1569  int tmpStatus = 0;
1570  fits_close_file(reinterpret_cast<fitsfile *>(fptr), &tmpStatus);
1571  }
1572  } else {
1573  throw LSST_EXCEPT(
1574  FitsError,
1575  (boost::format("Invalid mode '%s' given when opening file '%s'") % mode % filename).str());
1576  }
1577  if (behavior & AUTO_CHECK) {
1578  LSST_FITS_CHECK_STATUS(*this, boost::format("Opening file '%s' with mode '%s'") % filename % mode);
1579  }
1580 }
#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
def format(config, name=None, writeSourceLine=True, prefix="", verbose=False)
Definition: history.py:174

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

1583  : fptr(nullptr), status(0), behavior(behavior_) {
1584  using Reallocator = void *(*)(void *, std::size_t);
1585  // It's a shame this logic is essentially a duplicate of above, but the innards are different enough
1586  // we can't really reuse it.
1587  if (mode == "r" || mode == "rb") {
1588  fits_open_memfile(reinterpret_cast<fitsfile **>(&fptr), "unused", READONLY, &manager._ptr,
1589  &manager._len, 0, nullptr, // no reallocator or deltasize necessary for READONLY
1590  &status);
1591  } else if (mode == "w" || mode == "wb") {
1592  Reallocator reallocator = nullptr;
1593  if (manager._managed) reallocator = &std::realloc;
1594  fits_create_memfile(reinterpret_cast<fitsfile **>(&fptr), &manager._ptr, &manager._len, 0,
1595  reallocator, // use default deltasize
1596  &status);
1597  } else if (mode == "a" || mode == "ab") {
1598  Reallocator reallocator = nullptr;
1599  if (manager._managed) reallocator = &std::realloc;
1600  fits_open_memfile(reinterpret_cast<fitsfile **>(&fptr), "unused", READWRITE, &manager._ptr,
1601  &manager._len, 0, reallocator, &status);
1602  int nHdu = 0;
1603  fits_get_num_hdus(reinterpret_cast<fitsfile *>(fptr), &nHdu, &status);
1604  fits_movabs_hdu(reinterpret_cast<fitsfile *>(fptr), nHdu, nullptr, &status);
1605  if ((behavior & AUTO_CHECK) && (behavior & AUTO_CLOSE) && (status) && (fptr)) {
1606  // We're about to throw an exception, and the destructor won't get called
1607  // because we're in the constructor, so cleanup here first.
1608  int tmpStatus = 0;
1609  fits_close_file(reinterpret_cast<fitsfile *>(fptr), &tmpStatus);
1610  }
1611  } else {
1612  throw LSST_EXCEPT(FitsError,
1613  (boost::format("Invalid mode '%s' given when opening memory file at '%s'") % mode %
1614  manager._ptr)
1615  .str());
1616  }
1617  if (behavior & AUTO_CHECK) {
1619  *this, boost::format("Opening memory file at '%s' with mode '%s'") % manager._ptr % mode);
1620  }
1621 }
T realloc(T... args)

◆ ~Fits()

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

Definition at line 637 of file fits.h.

637  {
638  if ((fptr) && (behavior & AUTO_CLOSE)) closeFile();
639  }
void closeFile()
Close a FITS file.
Definition: fits.cc:1623

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

1127  {
1128  int nCols = 0;
1129  fits_get_num_cols(reinterpret_cast<fitsfile *>(fptr), &nCols, &status);
1130  std::string tform = makeColumnFormat<T>(size);
1131  fits_insert_col(reinterpret_cast<fitsfile *>(fptr), nCols + 1, const_cast<char *>(ttype.c_str()),
1132  const_cast<char *>(tform.c_str()), &status);
1133  if (behavior & AUTO_CHECK) {
1134  LSST_FITS_CHECK_STATUS(*this, boost::format("Adding column '%s' with size %d") % ttype % size);
1135  }
1136  return nCols;
1137 }
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 1140 of file fits.cc.

1140  {
1141  int nCols = addColumn<T>(ttype, size);
1142  updateColumnKey("TTYPE", nCols, ttype, comment);
1143  if (behavior & AUTO_CHECK) {
1144  LSST_FITS_CHECK_STATUS(*this, boost::format("Adding column '%s' with size %d") % ttype % size);
1145  }
1146  return nCols;
1147 }
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:691

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

1149  {
1150  long first = 0;
1151  fits_get_num_rows(reinterpret_cast<fitsfile *>(fptr), &first, &status);
1152  fits_insert_rows(reinterpret_cast<fitsfile *>(fptr), first, nRows, &status);
1153  if (behavior & AUTO_CHECK) {
1154  LSST_FITS_CHECK_STATUS(*this, boost::format("Adding %d rows to binary table") % nRows);
1155  }
1156  return first;
1157 }

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

1726  {
1727  auto fits = reinterpret_cast<fitsfile *>(fptr);
1728  if (getHdu() != 0 || countHdus() == 1) {
1729  return false; // Can't possibly be the PHU leading a compressed image
1730  }
1731  // Check NAXIS = 0
1732  int naxis;
1733  fits_get_img_dim(fits, &naxis, &status);
1734  if (behavior & AUTO_CHECK) {
1735  LSST_FITS_CHECK_STATUS(*this, "Checking NAXIS of PHU");
1736  }
1737  if (naxis != 0) {
1738  return false;
1739  }
1740  // Check first extension (and move back there when we're done if we're not compressed)
1741  HduMoveGuard move(*this, 1);
1742  bool isCompressed = fits_is_compressed_image(fits, &status);
1743  if (behavior & AUTO_CHECK) {
1744  LSST_FITS_CHECK_STATUS(*this, "Checking compression");
1745  }
1746  if (isCompressed) {
1747  move.disable();
1748  }
1749  return isCompressed;
1750 }
Fits * fits
Definition: FitsWriter.cc:90
int countHdus()
Return the number of HDUs in the file.
Definition: fits.cc:534
int getHdu()
Return the current HDU (0-indexed; 0 is the Primary HDU).
Definition: fits.cc:507
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 1435 of file fits.cc.

1435  {
1436  int imageType = 0;
1437  fits_get_img_equivtype(reinterpret_cast<fitsfile *>(fptr), &imageType, &status);
1438  if (behavior & AUTO_CHECK) LSST_FITS_CHECK_STATUS(*this, "Getting image type");
1440  if (imageType < 0) {
1441  return false; // can't represent floating-point with integer
1442  }
1444  if (isFitsImageTypeSigned(imageType)) {
1445  return FitsBitPix<T>::CONSTANT >= imageType;
1446  } else {
1447  // need extra bits to safely convert unsigned to signed
1448  return FitsBitPix<T>::CONSTANT > imageType;
1449  }
1450  } else {
1451  if (!isFitsImageTypeSigned(imageType)) {
1452  return FitsBitPix<T>::CONSTANT >= imageType;
1453  } else if (imageType == LONGLONG_IMG) {
1454  // workaround for CFITSIO not recognizing uint64 as
1455  // unsigned
1456  return FitsBitPix<T>::CONSTANT >= imageType;
1457  } else {
1458  return false;
1459  }
1460  }
1461  }
1462  // we allow all conversions to float and double, even if they lose precision
1463  return true;
1464 }

◆ closeFile()

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

Close a FITS file.

Definition at line 1623 of file fits.cc.

1623  {
1624  fits_close_file(reinterpret_cast<fitsfile *>(fptr), &status);
1625  fptr = nullptr;
1626 }

◆ countHdus()

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

Return the number of HDUs in the file.

Definition at line 534 of file fits.cc.

534  {
535  int n = 0;
536  fits_get_num_hdus(reinterpret_cast<fitsfile *>(fptr), &n, &status);
537  if (behavior & AUTO_CHECK) {
538  LSST_FITS_CHECK_STATUS(*this, "Getting number of HDUs in file.");
539  }
540  return n;
541 }

◆ countRows()

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

Return the number of row in a table.

Definition at line 1159 of file fits.cc.

1159  {
1160  long r = 0;
1161  fits_get_num_rows(reinterpret_cast<fitsfile *>(fptr), &r, &status);
1162  if (behavior & AUTO_CHECK) {
1163  LSST_FITS_CHECK_STATUS(*this, "Checking how many rows are in table");
1164  }
1165  return r;
1166 }

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

1240  {
1241  long naxes = 0;
1242  fits_create_img(reinterpret_cast<fitsfile *>(fptr), 8, 0, &naxes, &status);
1243  if (behavior & AUTO_CHECK) {
1244  LSST_FITS_CHECK_STATUS(*this, "Creating empty image HDU");
1245  }
1246 }

◆ 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 450 of file fits.h.

450  {
451  ndarray::Vector<long, N> nAxes(shape.reverse());
452  createImageImpl(bitpix, N, nAxes.elems);
453  }

◆ 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 462 of file fits.h.

462  {
463  long naxes[2] = {x, y};
464  createImageImpl(detail::Bitpix<PixelT>::value, 2, naxes);
465  }
double x
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 444 of file fits.h.

444  {
445  ndarray::Vector<long, N> nAxes(shape.reverse());
446  createImageImpl(detail::Bitpix<PixelT>::value, N, nAxes.elems);
447  }

◆ createTable()

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

Create a new binary table extension.

Definition at line 1117 of file fits.cc.

1117  {
1118  char *ttype = nullptr;
1119  char *tform = nullptr;
1120  fits_create_tbl(reinterpret_cast<fitsfile *>(fptr), BINARY_TBL, 0, 0, &ttype, &tform, nullptr, nullptr, &status);
1121  if (behavior & AUTO_CHECK) {
1122  LSST_FITS_CHECK_STATUS(*this, "Creating binary table");
1123  }
1124 }

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

781  {
782  char key[81]; // allow for terminating NUL
783  char value[81];
784  char comment[81];
785  int nKeys = 0;
786  fits_get_hdrspace(reinterpret_cast<fitsfile *>(fptr), &nKeys, nullptr, &status);
787  std::string keyStr;
788  std::string valueStr;
789  std::string commentStr;
790  int i = 1;
791  while (i <= nKeys) {
792  fits_read_keyn(reinterpret_cast<fitsfile *>(fptr), i, key, value, comment, &status);
793  // fits_read_keyn does not convert the key case on read, like other fits methods in cfitsio>=3.38
794  // We uppercase to try to be more consistent.
795  std::string upperKey(key);
796  boost::to_upper(upperKey);
797  if (upperKey.compare(key) != 0){
798  LOGLS_DEBUG("lsst.afw.fits",
799  boost::format("In %s, standardizing key '%s' to uppercase '%s' on read.") %
800  BOOST_CURRENT_FUNCTION % key % upperKey);
801  }
802  keyStr = upperKey;
803  valueStr = value;
804  commentStr = comment;
805  ++i;
806  while (valueStr.size() > 2 && valueStr[valueStr.size() - 2] == '&' && i <= nKeys) {
807  // we're using key to hold the entire record here; the actual key is safe in keyStr
808  fits_read_record(reinterpret_cast<fitsfile *>(fptr), i, key, &status);
809  if (strncmp(key, "CONTINUE", 8) != 0) {
810  // require both trailing '&' and CONTINUE to invoke long-string handling
811  break;
812  }
813  std::string card = key;
814  valueStr.erase(valueStr.size() - 2);
815  std::size_t firstQuote = card.find('\'');
816  if (firstQuote == std::string::npos) {
817  throw LSST_EXCEPT(
818  FitsError,
820  fptr, status,
821  boost::format("Invalid CONTINUE at header key %d: \"%s\".") % i % card));
822  }
823  std::size_t lastQuote = card.find('\'', firstQuote + 1);
824  if (lastQuote == std::string::npos) {
825  throw LSST_EXCEPT(
826  FitsError,
828  fptr, status,
829  boost::format("Invalid CONTINUE at header key %d: \"%s\".") % i % card));
830  }
831  valueStr += card.substr(firstQuote + 1, lastQuote - firstQuote);
832  std::size_t slash = card.find('/', lastQuote + 1);
833  if (slash != std::string::npos) {
834  commentStr += strip(card.substr(slash + 1));
835  }
836  ++i;
837  }
838  if (behavior & AUTO_CHECK) {
839  LSST_FITS_CHECK_STATUS(*this, boost::format("Reading key '%s'") % keyStr);
840  }
841  functor(keyStr, valueStr, commentStr);
842  }
843 }
#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:911
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:426
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 498 of file fits.cc.

498  {
499  std::string fileName = "<unknown>";
500  fitsfile *fd = reinterpret_cast<fitsfile *>(fptr);
501  if (fd != nullptr && fd->Fptr != nullptr && fd->Fptr->filename != nullptr) {
502  fileName = fd->Fptr->filename;
503  }
504  return fileName;
505 }

◆ getHdu()

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

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

Definition at line 507 of file fits.cc.

507  {
508  int n = 1;
509  fits_get_hdu_num(reinterpret_cast<fitsfile *>(fptr), &n);
510  return n - 1;
511 }

◆ getImageCompression()

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

Return the current image compression settings.

Definition at line 1495 of file fits.cc.

1495  {
1496  auto fits = reinterpret_cast<fitsfile *>(fptr);
1497  int compType = 0; // cfitsio compression type
1498  fits_get_compression_type(fits, &compType, &status);
1499  if (behavior & AUTO_CHECK) {
1500  LSST_FITS_CHECK_STATUS(*this, "Getting compression type");
1501  }
1502 
1503  ImageCompressionOptions::Tiles tiles = ndarray::allocate(MAX_COMPRESS_DIM);
1504  fits_get_tile_dim(fits, tiles.getNumElements(), tiles.getData(), &status);
1505  if (behavior & AUTO_CHECK) {
1506  LSST_FITS_CHECK_STATUS(*this, "Getting tile dimensions");
1507  }
1508 
1509  float quantizeLevel;
1510  fits_get_quantize_level(fits, &quantizeLevel, &status);
1511  if (behavior & AUTO_CHECK) {
1512  LSST_FITS_CHECK_STATUS(*this, "Getting quantizeLevel");
1513  }
1514 
1515  return ImageCompressionOptions(compressionAlgorithmFromCfitsio(compType), tiles, quantizeLevel);
1516 }
ImageCompressionOptions::CompressionAlgorithm compressionAlgorithmFromCfitsio(int cfitsio)
Convert compression algorithm from cfitsio to ImageCompressionOptions::CompressionAlgorithm.
ndarray::Array< long, 1, 1 > Tiles

◆ getImageDim()

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

Return the number of dimensions in the current HDU.

Definition at line 1422 of file fits.cc.

1422  {
1423  int nAxis = 0;
1424  fits_get_img_dim(reinterpret_cast<fitsfile *>(fptr), &nAxis, &status);
1425  if (behavior & AUTO_CHECK) LSST_FITS_CHECK_STATUS(*this, "Getting NAXIS");
1426  return nAxis;
1427 }

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

1466  {
1467  int bitpix = 0;
1468  fits_get_img_equivtype(reinterpret_cast<fitsfile *>(fptr), &bitpix, &status);
1469  if (behavior & AUTO_CHECK) LSST_FITS_CHECK_STATUS(*this, "Getting image type");
1470  // FITS' 'BITPIX' key is the number of bits in a pixel, but negative for
1471  // floats. But the above CFITSIO routine adds support for unsigned
1472  // integers by checking BZERO for an offset as well. So the 'bitpix' value
1473  // we get back from that should be the raw value for signed integers and
1474  // floats, but may be something else (still positive) for unsigned, and
1475  // hence we'll compare to some FITSIO constants to be safe looking at
1476  // integers.
1477  if (bitpix < 0) {
1478  return "float" + std::to_string(-bitpix);
1479  }
1480  switch (bitpix) {
1481  case BYTE_IMG: return "uint8";
1482  case SBYTE_IMG: return "int8";
1483  case SHORT_IMG: return "int16";
1484  case USHORT_IMG: return "uint16";
1485  case LONG_IMG: return "int32";
1486  case ULONG_IMG: return "uint32";
1487  case LONGLONG_IMG: return "int64";
1488  }
1489  throw LSST_EXCEPT(
1490  FitsError,
1491  (boost::format("Unrecognized BITPIX value: %d") % bitpix).str()
1492  );
1493 }
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 512 of file fits.h.

512  {
513  ndarray::Vector<long, N> nAxes(1);
514  getImageShapeImpl(N, nAxes.elems);
515  ndarray::Vector<ndarray::Size, N> shape;
516  for (int i = 0; i < N; ++i) shape[i] = nAxes[N - i - 1];
517  return shape;
518  }

◆ getTableArraySize() [1/2]

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

Return the size of an array column.

Definition at line 1217 of file fits.cc.

1217  {
1218  int typecode = 0;
1219  long result = 0;
1220  long width = 0;
1221  fits_get_coltype(reinterpret_cast<fitsfile *>(fptr), col + 1, &typecode, &result, &width, &status);
1222  if (behavior & AUTO_CHECK) {
1223  LSST_FITS_CHECK_STATUS(*this, boost::format("Looking up array size for column %d") % col);
1224  }
1225  return result;
1226 }
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 1228 of file fits.cc.

1228  {
1229  long result = 0;
1230  long offset = 0;
1231  fits_read_descript(reinterpret_cast<fitsfile *>(fptr), col + 1, row + 1, &result, &offset, &status);
1232  if (behavior & AUTO_CHECK) {
1233  LSST_FITS_CHECK_STATUS(*this, boost::format("Looking up array size for cell (%d, %d)") % row % col);
1234  }
1235  return result;
1236 }
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 541 of file fits.h.

541  {
542  ndarray::Vector<long, N> begin(offset.reverse());
543  ndarray::Vector<long, N> end(begin);
544  end += array.getShape().reverse();
545  ndarray::Vector<long, N> increment(1);
546  begin += increment; // first FITS pixel is 1, not 0
547  readImageImpl(N, array.getData(), begin.elems, end.elems, increment.elems);
548  }
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 774 of file fits.cc.

774  {
775  readKeyImpl(*this, key.c_str(), value);
776  if (behavior & AUTO_CHECK) {
777  LSST_FITS_CHECK_STATUS(*this, boost::format("Reading key '%s'") % key);
778  }
779 }

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

1087  {
1088  MetadataIterationFunctor f;
1089  f.strip = strip;
1090  f.set = &metadata;
1091  f.list = dynamic_cast<daf::base::PropertyList *>(&metadata);
1092  forEachKey(f);
1093 }
void forEachKey(HeaderIterationFunctor &functor)
Call a polymorphic functor for every key in the header.
Definition: fits.cc:781

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

1192  {
1193  int anynul = false;
1194  fits_read_col(reinterpret_cast<fitsfile *>(fptr), FitsTableType<T>::CONSTANT, col + 1, row + 1, 1,
1195  nElements, nullptr, value, &anynul, &status);
1196  if (behavior & AUTO_CHECK) {
1197  LSST_FITS_CHECK_STATUS(*this, boost::format("Reading value at table cell (%d, %d)") % row % col);
1198  }
1199 }

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

1201  {
1202  int anynul = false;
1203  long size = isVariableLength ? getTableArraySize(row, col) : getTableArraySize(col);
1204  // We can't directly write into a std::string until C++17.
1205  std::vector<char> buf(size + 1, 0);
1206  // cfitsio wants a char** because they imagine we might want an array of strings,
1207  // but we only want one element.
1208  char *tmp = &buf.front();
1209  fits_read_col(reinterpret_cast<fitsfile *>(fptr), TSTRING, col + 1, row + 1, 1, 1, nullptr, &tmp, &anynul,
1210  &status);
1211  if (behavior & AUTO_CHECK) {
1212  LSST_FITS_CHECK_STATUS(*this, boost::format("Reading value at table cell (%d, %d)") % row % col);
1213  }
1214  value = std::string(tmp);
1215 }
long getTableArraySize(int col)
Return the size of an array column.
Definition: fits.cc:1217

◆ 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 595 of file fits.h.

595  {
596  readTableArray(row, col, 1, &value);
597  }
void readTableArray(std::size_t row, int col, int nElements, T *value)
Read an array value from a binary table.
Definition: fits.cc:1192

◆ setHdu()

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

513  {
514  if (relative) {
515  fits_movrel_hdu(reinterpret_cast<fitsfile *>(fptr), hdu, nullptr, &status);
516  if (behavior & AUTO_CHECK) {
517  LSST_FITS_CHECK_STATUS(*this, boost::format("Incrementing HDU by %d") % hdu);
518  }
519  } else {
520  if (hdu != DEFAULT_HDU) {
521  fits_movabs_hdu(reinterpret_cast<fitsfile *>(fptr), hdu + 1, nullptr, &status);
522  }
523  if (hdu == DEFAULT_HDU && getHdu() == 0 && getImageDim() == 0) {
524  // want a silent failure here
525  int tmpStatus = status;
526  fits_movrel_hdu(reinterpret_cast<fitsfile *>(fptr), 1, nullptr, &tmpStatus);
527  }
528  if (behavior & AUTO_CHECK) {
529  LSST_FITS_CHECK_STATUS(*this, boost::format("Moving to HDU %d") % hdu);
530  }
531  }
532 }
int getImageDim()
Return the number of dimensions in the current HDU.
Definition: fits.cc:1422
const int DEFAULT_HDU
Specify that the default HDU should be read.
Definition: fitsDefaults.h:18

◆ setImageCompression()

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

Set compression options for writing FITS images.

See also
ImageCompressionContext

Definition at line 1518 of file fits.cc.

1518  {
1519  auto fits = reinterpret_cast<fitsfile *>(fptr);
1520  fits_unset_compression_request(fits, &status); // wipe the slate and start over
1522  allowImageCompression ? comp.algorithm : ImageCompressionOptions::NONE;
1523  fits_set_compression_type(fits, compressionAlgorithmToCfitsio(algorithm), &status);
1524  if (behavior & AUTO_CHECK) {
1525  LSST_FITS_CHECK_STATUS(*this, "Setting compression type");
1526  }
1527 
1528  if (algorithm == ImageCompressionOptions::NONE) {
1529  // Nothing else worth doing
1530  return;
1531  }
1532 
1533  fits_set_tile_dim(fits, comp.tiles.getNumElements(), comp.tiles.getData(), &status);
1534  if (behavior & AUTO_CHECK) {
1535  LSST_FITS_CHECK_STATUS(*this, "Setting tile dimensions");
1536  }
1537 
1538  if (comp.algorithm != ImageCompressionOptions::PLIO && std::isfinite(comp.quantizeLevel)) {
1539  fits_set_quantize_level(fits, comp.quantizeLevel, &status);
1540  if (behavior & AUTO_CHECK) {
1541  LSST_FITS_CHECK_STATUS(*this, "Setting quantization level");
1542  }
1543  }
1544 }
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 370 of file fits.h.

370  {
371  updateColumnKey(prefix, n, std::string(value));
372  }
std::string prefix
Definition: SchemaMapper.cc:72

◆ 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 365 of file fits.h.

365  {
366  updateColumnKey(prefix, n, std::string(value), comment);
367  }

◆ updateColumnKey() [3/4]

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

Definition at line 707 of file fits.cc.

707  {
708  updateKey((boost::format("%s%d") % prefix % (n + 1)).str(), value);
709  if (behavior & AUTO_CHECK) {
710  LSST_FITS_CHECK_STATUS(*this, boost::format("Updating key '%s%d': '%s'") % prefix % (n + 1) % value);
711  }
712 }
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:659

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

691  {
692  updateKey((boost::format("%s%d") % prefix % (n + 1)).str(), value, comment);
693  if (behavior & AUTO_CHECK) {
694  LSST_FITS_CHECK_STATUS(*this, boost::format("Updating key '%s%d': '%s'") % prefix % (n + 1) % value);
695  }
696 }

◆ updateKey() [1/4]

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

Definition at line 340 of file fits.h.

340 { 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 335 of file fits.h.

335  {
336  updateKey(key, std::string(value), comment);
337  }

◆ updateKey() [3/4]

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

Definition at line 675 of file fits.cc.

675  {
676  updateKeyImpl(*this, key.c_str(), value, nullptr);
677  if (behavior & AUTO_CHECK) {
678  LSST_FITS_CHECK_STATUS(*this, boost::format("Updating key '%s': '%s'") % key % value);
679  }
680 }

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

659  {
660  updateKeyImpl(*this, key.c_str(), value, comment.c_str());
661  if (behavior & AUTO_CHECK) {
662  LSST_FITS_CHECK_STATUS(*this, boost::format("Updating key '%s': '%s'") % key % value);
663  }
664 }

◆ writeColumnKey() [1/4]

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

Definition at line 384 of file fits.h.

384  {
385  writeColumnKey(prefix, n, std::string(value));
386  }
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:699

◆ 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 379 of file fits.h.

379  {
380  writeColumnKey(prefix, n, std::string(value), comment);
381  }

◆ writeColumnKey() [3/4]

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

Definition at line 715 of file fits.cc.

715  {
716  writeKey((boost::format("%s%d") % prefix % (n + 1)).str(), value);
717  if (behavior & AUTO_CHECK) {
718  LSST_FITS_CHECK_STATUS(*this, boost::format("Writing key '%s%d': '%s'") % prefix % (n + 1) % value);
719  }
720 }
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:667

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

699  {
700  writeKey((boost::format("%s%d") % prefix % (n + 1)).str(), value, comment);
701  if (behavior & AUTO_CHECK) {
702  LSST_FITS_CHECK_STATUS(*this, boost::format("Writing key '%s%d': '%s'") % prefix % (n + 1) % value);
703  }
704 }

◆ writeImage() [1/2]

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

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

1298  {
1299  auto fits = reinterpret_cast<fitsfile *>(fptr);
1300  ImageCompressionOptions const &compression =
1301  image.getBBox().getArea() > 0
1302  ? options.compression
1303  : ImageCompressionOptions(
1304  ImageCompressionOptions::NONE); // cfitsio can't compress empty images
1305  ImageCompressionContext comp(*this, compression); // RAII
1306  if (behavior & AUTO_CHECK) {
1307  LSST_FITS_CHECK_STATUS(*this, "Activating compression for write image");
1308  }
1309 
1310  ImageScale scale = options.scaling.determine(image, mask);
1311 
1312  // We need a place to put the image+header, and CFITSIO needs to know the dimenions.
1313  ndarray::Vector<long, 2> dims(image.getArray().getShape().reverse());
1314  createImageImpl(scale.bitpix == 0 ? detail::Bitpix<T>::value : scale.bitpix, 2, dims.elems);
1315 
1316  // Write the header
1319  if (header) {
1320  std::shared_ptr<daf::base::PropertySet> copy = header->deepCopy();
1321  copy->combine(wcsMetadata);
1322  header = copy;
1323  } else {
1324  header = wcsMetadata;
1325  }
1326  writeMetadata(*header);
1327 
1328  // Scale the image how we want it on disk
1329  ndarray::Array<T const, 2, 2> array = makeContiguousArray(image.getArray());
1330  auto pixels = scale.toFits(array, compression.quantizeLevel != 0, options.scaling.fuzz,
1331  options.compression.tiles, options.scaling.seed);
1332 
1333  // We only want cfitsio to do the scale and zero for unsigned 64-bit integer types. For those,
1334  // "double bzero" has sufficient precision to represent the appropriate value. We'll let
1335  // cfitsio handle it itself.
1336  // In all other cases, we will convert the image to use the appropriate scale and zero
1337  // (because we want to fuzz the numbers in the quantisation), so we don't want cfitsio
1338  // rescaling.
1340  fits_set_bscale(fits, 1.0, 0.0, &status);
1341  if (behavior & AUTO_CHECK) {
1342  LSST_FITS_CHECK_STATUS(*this, "Setting bscale,bzero");
1343  }
1344  }
1345 
1346  // Write the pixels
1347  int const fitsType = scale.bitpix == 0 ? FitsType<T>::CONSTANT : fitsTypeForBitpix(scale.bitpix);
1348  fits_write_img(fits, fitsType, 1, pixels->getNumElements(), const_cast<void *>(pixels->getData()),
1349  &status);
1350  if (behavior & AUTO_CHECK) {
1351  LSST_FITS_CHECK_STATUS(*this, "Writing image");
1352  }
1353 
1354  // Now write the headers we didn't want cfitsio to know about when we were writing the pixels
1355  // (because we don't want it using them to modify the pixels, and we don't want it overwriting
1356  // these values).
1358  std::isfinite(scale.bzero) && std::isfinite(scale.bscale) && (scale.bscale != 0.0)) {
1360  if (scale.bzero != 0.0) {
1361  fits_write_key_lng(fits, "BZERO", static_cast<long>(scale.bzero),
1362  "Scaling: MEMORY = BZERO + BSCALE * DISK", &status);
1363  }
1364  if (scale.bscale != 1.0) {
1365  fits_write_key_lng(fits, "BSCALE", static_cast<long>(scale.bscale),
1366  "Scaling: MEMORY = BZERO + BSCALE * DISK", &status);
1367  }
1368  } else {
1369  fits_write_key_dbl(fits, "BZERO", scale.bzero, 12, "Scaling: MEMORY = BZERO + BSCALE * DISK",
1370  &status);
1371  fits_write_key_dbl(fits, "BSCALE", scale.bscale, 12, "Scaling: MEMORY = BZERO + BSCALE * DISK",
1372  &status);
1373  }
1374  if (behavior & AUTO_CHECK) {
1375  LSST_FITS_CHECK_STATUS(*this, "Writing BSCALE,BZERO");
1376  }
1377  }
1378 
1379  if (scale.bitpix > 0 && !std::numeric_limits<T>::is_integer) {
1380  fits_write_key_lng(fits, "BLANK", scale.blank, "Value for undefined pixels", &status);
1381  fits_write_key_lng(fits, "ZDITHER0", options.scaling.seed, "Dithering seed", &status);
1382  fits_write_key_str(fits, "ZQUANTIZ", "SUBTRACTIVE_DITHER_1", "Dithering algorithm", &status);
1383  if (behavior & AUTO_CHECK) {
1384  LSST_FITS_CHECK_STATUS(*this, "Writing [Z]BLANK");
1385  }
1386  }
1387 
1388  // cfitsio says this is deprecated, but Pan-STARRS found that it was sometimes necessary, writing:
1389  // "This forces a re-scan of the header to ensure everything's kosher.
1390  // Without this, compressed HDUs have been written out with PCOUNT=0 and TFORM1 not correctly set."
1391  fits_set_hdustruc(fits, &status);
1392  if (behavior & AUTO_CHECK) {
1393  LSST_FITS_CHECK_STATUS(*this, "Finalizing header");
1394  }
1395 }
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:1095
T copy(T... args)
def 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:208
std::shared_ptr< daf::base::PropertyList > createTrivialWcsMetadata(std::string const &wcsName, lsst::geom::Point2I const &xy0)
Definition: wcsUtils.cc:48
std::string const wcsNameForXY0
Definition: ImageBase.h:70
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects.

◆ 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 477 of file fits.h.

477  {
478  writeImageImpl(makeContiguousArray(array).getData(), array.getNumElements());
479  }

◆ writeKey() [1/4]

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

Definition at line 358 of file fits.h.

358 { 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 353 of file fits.h.

353  {
354  writeKey(key, std::string(value), comment);
355  }

◆ writeKey() [3/4]

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

Definition at line 683 of file fits.cc.

683  {
684  writeKeyImpl(*this, key.c_str(), value, nullptr);
685  if (behavior & AUTO_CHECK) {
686  LSST_FITS_CHECK_STATUS(*this, boost::format("Writing key '%s': '%s'") % key % value);
687  }
688 }

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

667  {
668  writeKeyImpl(*this, key.c_str(), value, comment.c_str());
669  if (behavior & AUTO_CHECK) {
670  LSST_FITS_CHECK_STATUS(*this, boost::format("Writing key '%s': '%s'") % key % value);
671  }
672 }

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

1095  {
1096  using NameList = std::vector<std::string>;
1097  daf::base::PropertyList const *pl = dynamic_cast<daf::base::PropertyList const *>(&metadata);
1098  NameList paramNames;
1099  if (pl) {
1100  paramNames = pl->getOrderedNames();
1101  } else {
1102  paramNames = metadata.paramNames(false);
1103  }
1104  for (auto const &paramName : paramNames) {
1105  if (!isKeyIgnored(paramName, true)) {
1106  if (pl) {
1107  writeKeyFromProperty(*this, metadata, paramName, pl->getComment(paramName).c_str());
1108  } else {
1109  writeKeyFromProperty(*this, metadata, paramName);
1110  }
1111  }
1112  }
1113 }

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

1169  {
1170  fits_write_col(reinterpret_cast<fitsfile *>(fptr), FitsTableType<T>::CONSTANT, col + 1, row + 1, 1,
1171  nElements, const_cast<T *>(value), &status);
1172  if (behavior & AUTO_CHECK) {
1173  LSST_FITS_CHECK_STATUS(*this, boost::format("Writing %d-element array at table cell (%d, %d)") %
1174  nElements % row % col);
1175  }
1176 }

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

1178  {
1179  // cfitsio doesn't let us specify the size of a string, it just looks for null terminator.
1180  // Using std::string::c_str() guarantees that we have one. But we can't store arbitrary
1181  // data in a string field because cfitsio will also chop off anything after the first null
1182  // terminator.
1183  char const *tmp = value.c_str();
1184  fits_write_col(reinterpret_cast<fitsfile *>(fptr), TSTRING, col + 1, row + 1, 1, 1,
1185  const_cast<char const **>(&tmp), &status);
1186  if (behavior & AUTO_CHECK) {
1187  LSST_FITS_CHECK_STATUS(*this, boost::format("Writing value at table cell (%d, %d)") % row % col);
1188  }
1189 }

◆ writeTableScalar() [2/2]

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

Write a scalar value to a binary table.

Definition at line 583 of file fits.h.

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

Member Data Documentation

◆ behavior

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

Definition at line 651 of file fits.h.

◆ fptr

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

Definition at line 649 of file fits.h.

◆ status

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

Definition at line 650 of file fits.h.


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