GNU Astronomy Utilities



12.3.11.4 FITS header keywords

Each FITS extension/HDU contains a raw dataset which can either be a table or an image along with some header keywords. The keywords can be used to store meta-data about the actual dataset. The functions in this section describe Gnuastro’s high-level functions for reading and writing FITS keywords. Similar to all Gnuastro’s FITS-related functions, these functions are all wrappers for CFITSIO’s low-level functions.

The necessary meta-data (header keywords) for a particular dataset are commonly numerous, it is much more efficient to list them in one variable and call the reading/writing functions once. Hence the functions in this section use linked lists, a thorough introduction to them is given in Linked lists (list.h). To reading FITS keywords, these functions use a list of Gnuastro’s generic dataset format that is discussed in List of gal_data_t. To write FITS keywords we define the gal_fits_list_key_t node that is defined below.

Type (C struct): gal_fits_list_key_t

Structure for writing FITS keywords. This structure is used for one keyword and you do not need to set all elements. With the next element, you can link it to another keyword thus creating a linked list to add any number of keywords easily and at any step during your program (see Linked lists (list.h) for an introduction on lists). See the functions below for adding elements to the list.

typedef struct gal_fits_list_key_t
{
  int                        tfree; /* ==1, free title string.  */
  int                        kfree; /* ==1, free keyword name.  */
  int                        vfree; /* ==1, free keyword value. */
  int                        cfree; /* ==1, free comment.       */
  int                        ufree; /* ==1, free unit.          */
  uint8_t                     type; /* Keyword value type.      */
  char                      *title; /* !=NULL, only print title.*/
  char                    *keyname; /* Keyword Name.            */
  void                      *value; /* Keyword value.           */
  char                    *comment; /* Keyword comment.         */
  char                       *unit; /* Keyword unit.            */
  struct gal_fits_list_key_t *next; /* Pointer next keyword.    */
} gal_fits_list_key_t;
Function:
int
gal_fits_key_exists_fptr (fitsfile *fptr, char *keyname)

Return 1 (true) if the opened FITS file pointer contains the requested keyword and 0 (false) otherwise.

Function:
void *
gal_fits_key_img_blank (uint8_t type)

Returns a pointer to an allocated space containing the value to the FITS BLANK header keyword, when the input array has a type of type. This is useful when you want to write the BLANK keyword using CFITSIO’s fits_write_key function.

According to the FITS standard: “If the BSCALE and BZERO keywords do not have the default values of 1.0 and 0.0, respectively, then the value of the BLANK keyword must equal the actual value in the FITS data array that is used to represent an undefined pixel and not the corresponding physical value”. Therefore a special BLANK value is needed for datasets containing signed 8-bit, unsigned 16-bit, unsigned 32-bit, and unsigned 64-bit integers (types that are defined with BSCALE and BZERO in the FITS standard).

Not usable when reading a dataset: As quoted from the FITS standard above, the value returned by this function can only be generically used for the writing of the BLANK keyword header. It must not be used as the blank pointer when when reading a FITS array using CFITSIO. When reading an array with CFITSIO, you can use gal_blank_alloc_write to generate the necessary pointer.

Function:
void
gal_fits_key_clean_str_value (char *string)

Remove the single quotes and possible extra spaces around the keyword values that CFITSIO returns when reading a string keyword. CFITSIO does not remove the two single quotes around the string value of a keyword. Hence the strings it reads are like: 'value ', or 'some_very_long_value'. To use the value during your processing, it is commonly necessary to remove the single quotes (and possible extra spaces). This function will do this within the allocated space of the string.

Function:
char *
gal_fits_key_date_to_struct_tm (char *fitsdate, struct tm *tp)

Parse fitsdate as a FITS date format string (most generally: YYYY-MM-DDThh:mm:ss.ddd...) into the C library’s broken-down time structure, or struct tm (declared in time.h) and return a pointer to a newly allocated array for the sub-second part of the format (.ddd...). Therefore it needs to be freed afterwards (if it is not NULL) When there is no sub-second portion, this pointer will be NULL.

This is a relatively low-level function, an easier function to use is gal_fits_key_date_to_seconds which will return the sub-seconds as double precision floating point.

Note that the FITS date format mentioned above is the most complete representation. The following two formats are also acceptable: YYYY-MM-DDThh:mm:ss and YYYY-MM-DD. This option can also interpret the older FITS date format where only two characters are given to the year and the date format is reversed (DD/MM/YYThh:mm:ss.ddd...). In this case (following the GNU C Library), this option will make the following assumption: values 68 to 99 correspond to the years 1969 to 1999, and values 0 to 68 as the years 2000 to 2068.

Function:
size_t
gal_fits_key_date_to_seconds (char *fitsdate, char **subsecstr, double *subsec)

Return the Unix epoch time (number of seconds that have passed since 00:00:00 Thursday, January 1st, 1970) corresponding to the FITS date format string fitsdate (see description of gal_fits_key_date_to_struct_tm above). This function will return GAL_BLANK_SIZE_T if the broken-down time could not be converted to seconds.

The Unix epoch time is in units of seconds, but the FITS date format allows sub-second accuracy. The last two arguments are for the optional sub-second portion. If you do not want sub-second information, just set the second argument to NULL.

If fitsdate contains sub-second accuracy and subsecstr!=NULL, then the starting of the sub-second part’s string is stored in subsecstr (malloc’ed), and subsec will be the corresponding numerical value (between 0 and 1, in double precision floating point). So to avoid leaking memory, if a sub-second string is requested, it must be freed after calling this function. When a sub-second string does not exist (and it is requested), then a value of NULL and NaN will be written in *subsecstr and *subsec respectively.

This is a very useful function for operations on the FITS date values, for example, sorting FITS files by their dates, or finding the time difference between two FITS files. The advantage of working with the Unix epoch time is that you do not have to worry about calendar details (such as the number of days in different months or leap years).

Function:
void
gal_fits_key_read_from_ptr (fitsfile *fptr, gal_data_t *keysll, int readcomment, int readunit)

Read the list of keyword values from a FITS pointer. The input should be a linked list of Gnuastro’s generic data container (gal_data_t). Before calling this function, you just have to set the name, and optionally, the desired type of the value of each keyword. The given name value will be directly passed to CFITSIO to read the desired keyword name. This function will allocate space to keep the value. If no pre-defined type is requested for a certain keyword’s value, the smallest possible type to host the value will be found and used. If readcomment and readunit are non-zero, this function will also try to read the possible comments and units of the keyword.

Here is one example of using this function:

/* Allocate an array of datasets. */
gal_data_t *keysll=gal_data_array_calloc(N);

/* Make the array usable as a list too (by setting `next'). */
for(i=0;i<N-1;++i) keysll[i].next=&keysll[i+1];

/* Fill the datasets with a `name' and a `type'. */
keysll[0].name="NAME1";     keysll[0].type=GAL_TYPE_INT32;
keysll[1].name="NAME2";     keysll[1].type=GAL_TYPE_STRING;
...
...

/* Call this function. */
gal_fits_key_read_from_ptr(fptr, keysll, 0, 0);

/* Use the values as you like... */

/* Free all the allocated spaces. Note that `name' was not
   allocated in this example, so we should explicitly set
   it to NULL before calling `gal_data_array_free'. */
for(i=0;i<N;++i) keysll[i].name=NULL;
gal_data_array_free(keysll, N, 1);

If the array pointer of each keyword’s dataset is not NULL, then it is assumed that the space to keep the value has already been allocated. If it is NULL, space will be allocated for the value by this function.

Strings need special consideration: the reason is that generally, gal_data_t needs to also allow for array of strings (as it supports arrays of integers for example). Hence when reading a string value, two allocations may be done by this function (one if array!=NULL).

Therefore, when using the values of strings after this function, keysll[i].array must be interpreted as char **: one allocation for the pointer, one for the actual characters. If you use something like the example, above you do not have to worry about the freeing, gal_data_array_free will free both allocations. So to read a string, one easy way would be the following:

char *str, **strarray;
strarr = keysll[i].array;
str    = strarray[0];

If CFITSIO is unable to read a keyword for any reason the status element of the respective gal_data_t will be non-zero. If it is zero, then the keyword was found and successfully read. Otherwise, it is a CFITSIO status value. You can use CFITSIO’s error reporting tools or gal_fits_io_error (see FITS Macros, errors and filenames) for reporting the reason of the failure. A tip: when the keyword does not exist, CFITSIO’s status value will be KEY_NO_EXIST.

CFITSIO will start searching for the keywords from the last place in the header that it searched for a keyword. So it is much more efficient if the order that you ask for keywords is based on the order they are stored in the header.

Function:
void
gal_fits_key_read (char *filename, char *hdu, gal_data_t *keysll, int readcomment, int readunit, char *hdu_option_name)

Same as gal_fits_read_keywords_fptr (see above), but accepts the filename and HDU as input instead of an already opened CFITSIO fitsfile pointer.

Function:
void
gal_fits_key_list_add (gal_fits_list_key_t **list, uint8_t type, char *keyname, int kfree, void *value, int vfree, char *comment, int cfree, char *unit, int ufree)

Add a keyword to the top of list of header keywords that need to be written into a FITS file. In the end, the keywords will have to be freed, so it is important to know before hand if they were allocated or not (hence the presence of the arguments ending in free). If the space for the respective element is not allocated, set these arguments to 0 (zero).

You can call this function multiple times on a single list add several keys that will be written in one call to gal_fits_key_write or gal_fits_key_write_in_ptr. However, the resulting list will be a last-in-first-out list (for more on lists, see Linked lists (list.h)). Hence, the written keys will have the inverse order of your calls to this function. To avoid this problem, you can either use gal_fits_key_list_add_end instead (which will add each key to the end of the list, not to the top like this function). Alternatively, you can use gal_fits_key_list_reverse after adding all the keys with this function.

Important note for strings: the value should be the pointer to the string its-self (char *), not a pointer to a pointer (char **).

Function:
void
gal_fits_key_list_add_end (gal_fits_list_key_t **list, uint8_t type, char *keyname, int kfree, void *value, int vfree, char *comment, int cfree, char *unit, int ufree)

Similar to gal_fits_key_list_add, but add the given keyword to the end of the list, see the description of gal_fits_key_list_add for more. Use this function if you want the keywords to be written in the same order that you add nodes to the list of keywords.

Function:
void
gal_fits_key_list_title_add (gal_fits_list_key_t **list, char *title, int tfree)

Add a special “title” keyword (with the title string) to the top of the keywords list. If cfree is non-zero, the space allocated for comment will be freed immediately after writing the keyword (in another function).

Function:
void
gal_fits_key_list_title_add_end (gal_fits_list_key_t **list, char *title, int tfree)

Similar to gal_fits_key_list_title_add, but put the comments at the end of the list.

Function:
void
gal_fits_key_list_fullcomment_add (gal_fits_list_key_t **list, char *comment, int fcfree)

Add a COMMENT keyword to the top of the keywords list. If the comment is longer than 70 characters, CFITSIO will automatically break it into multiple COMMENT keywords. If fcfree is non-zero, the space allocated for comment will be freed immediately after writing the keyword (in another function).

Function:
void
gal_fits_key_list_fullcomment_add_end (gal_fits_list_key_t **list, char *comment, int fcfree)

Similar to gal_fits_key_list_comment_add, but put the comments at the end of the list.

Function:
void
gal_fits_key_list_add_date (gal_fits_list_key_t **keylist, char *comment)

Add a DATE keyword to the input list of keywords containing the date this function was activated in the format of YYYY-MM-DDThh:mm:ss. This function will also add a DATEUTC keyword that specifies if the date is in UTC or local time (this depends on CFITSIO being able to detect UTC in the running operating system or not).

The comment of the keyword should also be specified as the second argument. The comment is useful to inform users what this date refers to; for example the program starting time, its ending time, or etc. For more, see the description under DATE in Output FITS files.

Function:
void
gal_fits_key_list_add_software_versions (gal_fits_list_key_t **keylist)

Add the version of Gnuastro Mandatory dependencies to the list of keywords. Each software’s keyword has the same name as the software itself (for example GNUASTRO or GSL. For the full list of software, see Output FITS files.

Function:
void
gal_fits_key_list_add_git_commit (gal_fits_list_key_t **keylist)

If the optional libgit2 dependency is installed and your program is being run in a directory that is under version control, a COMMIT keyword will be added on the top of the list of keywords. For more, see the description of COMMIT in Output FITS files.

Function:
void
gal_fits_key_list_reverse (gal_fits_list_key_t **list)

Reverse the input list of keywords.

Function:
void
gal_fits_key_write_title_in_ptr (char *title, fitsfile *fptr)

Add two lines of “title” keywords to the given CFITSIO fptr pointer. The first line will be blank and the second will have the string in title roughly in the middle of the line (a fixed distance from the start of the keyword line). A title in the list of keywords helps in classifying the keywords into groups and inspecting them by eye. If title==NULL, this function will not do anything.

Function:
void
gal_fits_key_write_filename (char *keynamebase, char *filename, gal_fits_list_key_t **list, int top1end0, int quiet)

Put filename into the gal_fits_list_key_t list (possibly broken up into multiple keywords) to later write into a HDU header. The keynamebase string will be appended with a _N (N>0) and used as the keyword name. If top1end0!=0, then the keywords containing the filename will be added to the top of the list.

The FITS standard sets a maximum length of 69 characters for the string values of a keyword262. This creates problems with file names (which include directories) because file names/addresses can become longer than the maximum number of characters in a FITS keyword (around 70 characters). Therefore, when filename is longer than the maximum length of a FITS keyword value, this function will break it into several keywords (breaking up the string on directory separators). So the full file/directory address (including directories) can be longer than 69 characters. However, if a single file or directory name (within a larger address) is longer than 69 characters, this function will truncate the name and print a warning. If quiet!=0, then the warning will not be printed.

Function:
void
gal_fits_key_write_wcsstr (fitsfile *fptr, struct wcsprm wcs, char *wcsstr, int nkeyrec)

Write the WCS header string (produced with WCSLIB’s wcshdo function) into the CFITSIO fitsfile pointer. nkeyrec is the number of FITS header keywords in wcsstr. This function will put a few blank keyword lines along with a comment WCS information before writing each keyword record.

Function:
void
gal_fits_key_write (gal_fits_list_key_t **keylist, char *filename, char *hdu, char *hdu_option_name, int freekeys, int create_fits_not_exists)

Write the list of keywords in keylist into the hdu extension of the file called filename. If the file may not exist before this function is activated, set create_fits_not_exists to non-zero and set the HDU to "0". If the keywords should be freed after they are written, set the freekeys value to non-zero. For more on hdu_option_name see the description of gal_array_read in Array input output.

The list nodes are meant to be dynamically allocated (because they will be freed after being written). We thus recommend using the gal_fits_key_list_add or gal_fits_key_list_add_end to create and fill the list. Below is one fully working example of using this function to write a keyword into an existing FITS file.

#include <stdio.h>
#include <stdlib.h>
#include <gnuastro/fits.h>

int main()
{
  char *filename="test.fits";
  gal_fits_list_key_t *keylist=NULL;

  char *unit="unit";
  float value=123.456;
  char *keyname="MYKEY";
  char *comment="A good description of the key";
  gal_fits_key_list_add_end(&keylist, GAL_TYPE_FLOAT32, keyname, 0,
                            &value, 0, comment, 0, unit, 0);
  gal_fits_key_list_title_add(&keylist, "Matching metadata", 0);
  gal_fits_key_write(&keylist, filename, "1", "NONE", 1, 0);
  return EXIT_SUCCESS;
}
Function:
void
gal_fits_key_write_in_ptr (gal_fits_list_key_t **keylist, fitsfile *fptr, int freekeys)

Write the list of keywords in keylist into the given CFITSIO fitsfile pointer and free keylist. For more on the input keylist, see the description and example for gal_fits_key_write, above.

Function:
gal_list_str_t *
gal_fits_with_keyvalue (gal_list_str_t *files, char *hdu, char *name, gal_list_str_t *values, char *hdu_option_name)

Given a list of FITS file names (files), a certain HDU (hdu), a certain keyword name (name), and a list of acceptable values (values), return the subset of file names where the requested keyword name has one of the acceptable values. For more on hdu_option_name see the description of gal_array_read in Array input output.

Function:
gal_list_str_t *
gal_fits_unique_keyvalues (gal_list_str_t *files, char *hdu, char *name, char *hdu_option_name)

Given a list of FITS file names (files), a certain HDU (hdu), a certain keyword name (name), return the list of unique values to that keyword name in all the files. For more on hdu_option_name see the description of gal_array_read in Array input output.


Footnotes

(262)

The limit is actually 71 characters (which is the full 80 character length, subtracted by 8 for the keyword name and one character for the =). However, for strings, FITS also requires two single quotes.