[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[gnuastro-commits] master 7b33afa 043/125: FITS ascii and binary table I
From: |
Mohammad Akhlaghi |
Subject: |
[gnuastro-commits] master 7b33afa 043/125: FITS ascii and binary table I/O done with tests |
Date: |
Sun, 23 Apr 2017 22:36:33 -0400 (EDT) |
branch: master
commit 7b33afa150109ebaed0dc91e11a94c704a9b9536
Author: Mohammad Akhlaghi <address@hidden>
Commit: Mohammad Akhlaghi <address@hidden>
FITS ascii and binary table I/O done with tests
The FITS standard doesn't have any code to store `signed char', `unsigned
short', or `unsigned int' types. So they suggest using special values for
the `TSCALn' (to scale a column values) and `TZEROn' (to shift the column
values) keywords to let CFITSIO know that we are dealing with one of these
types instead of their unsigned/signed counterparts.
While CFITSIO does do this internally, we also need to do this outside
CFITSIO because the space/type to keep the values must already be
allocated/known. So `gal_fits_table_info' now reads the `TZEROn' and
`TSCALn' keywords also and the new function
`fits_correct_bin_table_int_types' is in charge of checking these two
values and correcting the type if it is necessary. With this correction
(and those in the last commit), the example table in
`tests/table/table.txt' which contains all types and blank values and etc
can now be read as an ASCII or binary FITS file and converted back into a
plain text file.
The test table was also corrected to be usable with the default values as
discussed in the comments above the table. Also, two tests were added to
first read this table as an ASCII FITS table, then convert that back to a
plain text table (two similar tests with Binary FITS tables alreay
existed). All four of these tests now pass (on my system at least).
---
lib/fits.c | 110 +++++++++++++++++++++++++++++++++++++--
lib/gnuastro/table.h | 2 +-
tests/Makefile.am | 33 ++++++------
tests/table/fits-ascii-to-txt.sh | 51 ++++++++++++++++++
tests/table/table.txt | 39 ++++++++------
tests/table/txt-to-fits-ascii.sh | 51 ++++++++++++++++++
6 files changed, 250 insertions(+), 36 deletions(-)
diff --git a/lib/fits.c b/lib/fits.c
index 9088f87..693b410 100644
--- a/lib/fits.c
+++ b/lib/fits.c
@@ -1734,6 +1734,53 @@ set_display_format(char *tdisp, gal_data_t *data, char
*filename, char *hdu,
+/* The FITS standard for binary tables (not ASCII tables) does not allow
+ unsigned types for short, int and long types, or signed char! So it has
+ `TSCALn' and `TZEROn' to scale the signed types to an unsigned type. It
+ does this internally, but since we need to define our data type and
+ allocate space for it before actually reading the array, it is necessary
+ to do this setting here. */
+static void
+fits_correct_bin_table_int_types(gal_data_t *allcols, int tfields,
+ int *tscal, long long *tzero)
+{
+ size_t i;
+
+ for(i=0;i<tfields;++i)
+ {
+ /* If TSCALn is not 1, the reason for it isn't to use a different
+ signed/unsigned type, so don't change anything. */
+ if(tscal[i]!=1) continue;
+
+ /* For a check
+ printf("Column %zu initial type: %s (s: %d, z: %lld)\n", i+1,
+ gal_data_type_as_string(allcols[i].type, 1), tscal[i], tzero[i]);
+ */
+
+ /* Correct the type based on the initial read type and the value to
+ tzero. If tzero is any other value, then again, its not a type
+ conversion, so just ignore it. */
+ if(allcols[i].type==GAL_DATA_TYPE_UCHAR && tzero[i]==SCHAR_MIN)
+ allcols[i].type = GAL_DATA_TYPE_CHAR;
+
+ else if ( allcols[i].type==GAL_DATA_TYPE_SHORT
+ && tzero[i] == -(long long)SHRT_MIN )
+ allcols[i].type = GAL_DATA_TYPE_USHORT;
+
+ else if (allcols[i].type==GAL_DATA_TYPE_LONG
+ && tzero[i] == -(long long)INT_MIN)
+ allcols[i].type = GAL_DATA_TYPE_UINT;
+
+ /* For a check
+ printf("Column %zu corrected type: %s\n", i+1,
+ gal_data_type_as_string(allcols[i].type, 1));
+ */
+ }
+}
+
+
+
+
/* See the descriptions of `gal_table_info'. */
gal_data_t *
@@ -1745,8 +1792,9 @@ gal_fits_table_info(char *filename, char *hdu, size_t
*numcols,
char *tailptr;
fitsfile *fptr;
size_t i, index;
+ long long *tzero;
gal_data_t *allcols;
- int status=0, datatype;
+ int status=0, datatype, *tscal;
char keyname[FLEN_KEYWORD]="XXXXXXXXXXXXX", value[FLEN_VALUE];
/* Open the FITS file and get the basic information. */
@@ -1760,6 +1808,20 @@ gal_fits_table_info(char *filename, char *hdu, size_t
*numcols,
allcols=gal_data_calloc_dataarray(tfields);
+ /* See comments of `fits_correct_bin_table_int_types'. Here we are
+ allocating the space to keep these values. */
+ errno=0;
+ tscal=calloc(tfields, sizeof *tscal);
+ if(tscal==NULL)
+ error(EXIT_FAILURE, errno, "%zu bytes for tscal in "
+ "`gal_fits_table_info'", tfields*sizeof *tscal);
+ errno=0;
+ tzero=calloc(tfields, sizeof *tzero);
+ if(tzero==NULL)
+ error(EXIT_FAILURE, errno, "%zu bytes for tzero in "
+ "`gal_fits_table_info'", tfields*sizeof *tzero);
+
+
/* Read all the keywords one by one and if they match, then put them in
the correct value. Note that we are starting from keyword 9 because
according to the FITS standard, the first 8 keys in a FITS table are
@@ -1805,7 +1867,7 @@ gal_fits_table_info(char *filename, char *hdu, size_t
*numcols,
if(*tabletype==GAL_TABLE_TYPE_AFITS)
{
repeat=strtol(&value[2], &tailptr, 0);
- if(tailptr=='\0')
+ if(*tailptr!='\0')
error(EXIT_FAILURE, 0, "%s (hdu: %s): the value to "
"keyword `%s' (`%s') is not in `Aw' format "
"(for strings) as required by the FITS "
@@ -1816,6 +1878,34 @@ gal_fits_table_info(char *filename, char *hdu, size_t
*numcols,
}
}
+ /* COLUMN SCALE FACTOR. */
+ else if(strncmp(keyname, "TSCAL", 5)==0)
+ {
+ index = strtoul(&keyname[5], &tailptr, 10) - 1;
+ if(index<tfields)
+ {
+ tscal[index]=strtol(value, &tailptr, 0);
+ if(*tailptr!='\0')
+ error(EXIT_FAILURE, 0, "%s (hdu: %s): value to %s keyword "
+ "(`%s') couldn't be read as a number", filename, hdu,
+ keyname, value);
+ }
+ }
+
+ /* COLUMN ZERO VALUE (for signed/unsigned types). */
+ else if(strncmp(keyname, "TZERO", 5)==0)
+ {
+ index = strtoul(&keyname[5], &tailptr, 10) - 1;
+ if(index<tfields)
+ {
+ tzero[index]=strtoll(value, &tailptr, 0);
+ if(*tailptr!='\0')
+ error(EXIT_FAILURE, 0, "%s (hdu: %s): value to %s keyword "
+ "(`%s') couldn't be read as a number", filename, hdu,
+ keyname, value);
+ }
+ }
+
/* COLUMN NAME. All strings in CFITSIO start and finish with single
quotation marks, CFITSIO puts them in itsself, so if we don't
remove them here, we might have duplicates later, its easier to
@@ -1884,8 +1974,15 @@ gal_fits_table_info(char *filename, char *hdu, size_t
*numcols,
keyname);
}
}
+
+ /* Column zero. */
}
+ /* Correct integer types, then free the allocated arrays. */
+ fits_correct_bin_table_int_types(allcols, tfields, tscal, tzero);
+ free(tscal);
+ free(tzero);
+
/* Close the FITS file and report an error if we had any. */
fits_close_file(fptr, &status);
gal_fits_io_error(status, NULL);
@@ -2094,6 +2191,7 @@ fits_write_tnull_tcomm(fitsfile *fptr, gal_data_t *col,
int tabletype,
int status=0;
char *keyname, *bcomment;
+ /* Write the NULL value */
switch(tabletype)
{
case GAL_TABLE_TYPE_AFITS:
@@ -2106,11 +2204,15 @@ fits_write_tnull_tcomm(fitsfile *fptr, gal_data_t *col,
int tabletype,
break;
case GAL_TABLE_TYPE_BFITS:
+ /* FITS binary tables don't accept NULL values for floating point or
+ string columns. For floating point is must be NaN and for strings
+ it is a blank string. */
if( col->type!=GAL_DATA_TYPE_FLOAT
- && col->type!=GAL_DATA_TYPE_DOUBLE )
+ && col->type!=GAL_DATA_TYPE_DOUBLE
+ && col->type!=GAL_DATA_TYPE_STRING )
{
- asprintf(&keyname, "TNULL%zu", colnum);
blank=gal_data_alloc_blank(col->type);
+ asprintf(&keyname, "TNULL%zu", colnum);
fits_write_key(fptr, gal_fits_type_to_datatype(col->type),
keyname, blank, "blank value for this column",
&status);
diff --git a/lib/gnuastro/table.h b/lib/gnuastro/table.h
index 1df6e5a..6acc21a 100644
--- a/lib/gnuastro/table.h
+++ b/lib/gnuastro/table.h
@@ -59,7 +59,7 @@ __BEGIN_C_DECLS /* From C++ preparations */
#define GAL_TABLE_DEF_STR_WIDTH 6
#define GAL_TABLE_DEF_INT_WIDTH 6
#define GAL_TABLE_DEF_LINT_WIDTH 10
-#define GAL_TABLE_DEF_FLT_WIDTH 10
+#define GAL_TABLE_DEF_FLT_WIDTH 12
#define GAL_TABLE_DEF_DBL_WIDTH 18
#define GAL_TABLE_DEF_INT_PRECISION 0
diff --git a/tests/Makefile.am b/tests/Makefile.am
index e4b3113..b852146 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -65,21 +65,22 @@ multithread_SOURCES = lib/multithread.c
# The actual test scripts that are run:
-TESTS = $(check_PROGRAMS) prepconf.sh mkprof/mosaic1.sh mkprof/mosaic2.sh \
- mkprof/mosaic3.sh mkprof/mosaic4.sh mkprof/radeccat.sh imgcrop/imgcat.sh \
- imgcrop/wcscat.sh imgcrop/xcyc.sh imgcrop/xcycnoblank.sh \
- imgcrop/section.sh imgcrop/radec.sh imgcrop/imgpolygon.sh \
- imgcrop/imgoutpolygon.sh imgcrop/wcspolygon.sh convertt/fitstotxt.sh \
- convertt/fitstojpeg.sh convertt/blankch.sh convertt/jpegtotxt.sh \
- convertt/fitstojpegcmyk.sh convertt/jpegtofits.sh convertt/fitstopdf.sh \
- convolve/spatial.sh convolve/frequency.sh imgwarp/imgwarp_scale.sh \
- imgwarp/homographic.sh mknoise/addnoise.sh mkprof/ellipticalmasks.sh \
- mkprof/inputascanvas.sh header/write.sh header/print.sh header/update.sh \
- header/delete.sh imgstat/basicstats.sh subtractsky/subtractsky.sh \
- noisechisel/noisechisel.sh mkcatalog/simple.sh mkcatalog/aperturephot.sh \
- arithmetic/snimage.sh arithmetic/onlynumbers.sh arithmetic/where.sh \
- arithmetic/or.sh cosmiccal/simpletest.sh table/txt-to-fits-binary.sh \
- table/fits-binary-to-txt.sh
+TESTS = $(check_PROGRAMS) prepconf.sh mkprof/mosaic1.sh mkprof/mosaic2.sh \
+ mkprof/mosaic3.sh mkprof/mosaic4.sh mkprof/radeccat.sh imgcrop/imgcat.sh \
+ imgcrop/wcscat.sh imgcrop/xcyc.sh imgcrop/xcycnoblank.sh \
+ imgcrop/section.sh imgcrop/radec.sh imgcrop/imgpolygon.sh \
+ imgcrop/imgoutpolygon.sh imgcrop/wcspolygon.sh convertt/fitstotxt.sh \
+ convertt/fitstojpeg.sh convertt/blankch.sh convertt/jpegtotxt.sh \
+ convertt/fitstojpegcmyk.sh convertt/jpegtofits.sh convertt/fitstopdf.sh \
+ convolve/spatial.sh convolve/frequency.sh imgwarp/imgwarp_scale.sh \
+ imgwarp/homographic.sh mknoise/addnoise.sh mkprof/ellipticalmasks.sh \
+ mkprof/inputascanvas.sh header/write.sh header/print.sh header/update.sh \
+ header/delete.sh imgstat/basicstats.sh subtractsky/subtractsky.sh \
+ noisechisel/noisechisel.sh mkcatalog/simple.sh mkcatalog/aperturephot.sh \
+ arithmetic/snimage.sh arithmetic/onlynumbers.sh arithmetic/where.sh \
+ arithmetic/or.sh cosmiccal/simpletest.sh table/txt-to-fits-binary.sh \
+ table/fits-binary-to-txt.sh table/txt-to-fits-ascii.sh \
+ table/fits-ascii-to-txt.sh
@@ -130,6 +131,8 @@ mkprof/mosaic4.sh: prepconf.sh.log
mkprof/radeccat.sh: prepconf.sh.log
table/txt-to-fits-binary.sh: prepconf.sh.log
table/fits-binary-to-txt.sh: table/txt-to-fits-binary.sh.log
+table/txt-to-fits-ascii.sh: prepconf.sh.log
+table/fits-ascii-to-txt.sh: table/txt-to-fits-ascii.sh.log
imgcrop/imgcat.sh: mkprof/mosaic1.sh.log
imgcrop/wcscat.sh: mkprof/mosaic1.sh.log mkprof/mosaic2.sh.log \
mkprof/mosaic3.sh.log mkprof/mosaic4.sh.log
diff --git a/tests/table/fits-ascii-to-txt.sh b/tests/table/fits-ascii-to-txt.sh
new file mode 100755
index 0000000..96df459
--- /dev/null
+++ b/tests/table/fits-ascii-to-txt.sh
@@ -0,0 +1,51 @@
+# Convert an ASCII table to a binary table
+#
+# See the Tests subsection of the manual for a complete explanation
+# (in the Installing gnuastro section).
+#
+# Original author:
+# Mohammad Akhlaghi <address@hidden>
+# Contributing author(s):
+#
+# Copying and distribution of this file, with or without modification,
+# are permitted in any medium without royalty provided the copyright
+# notice and this notice are preserved. This file is offered as-is,
+# without any warranty.
+
+
+
+
+
+# Preliminaries
+# =============
+#
+# Set the variabels (The executable is in the build tree). Do the
+# basic checks to see if the executable is made or if the defaults
+# file exists (basicchecks.sh is in the source tree).
+prog=table
+execname=../bin/$prog/ast$prog
+table=ascii-table.fits
+
+
+
+
+
+# Skip?
+# =====
+#
+# If the dependencies of the test don't exist, then skip it. There are two
+# types of dependencies:
+#
+# - The executable was not made (for example due to a configure option),
+#
+# - The input data was not made (for example the test that created the
+# data file failed).
+if [ ! -f $execname ] || [ ! -f $img ]; then exit 77; fi
+
+
+
+
+
+# Actual test script
+# ==================
+$execname $table --output=from-ascii-table.txt -h1
diff --git a/tests/table/table.txt b/tests/table/table.txt
index 7538dd2..5c5f670 100644
--- a/tests/table/table.txt
+++ b/tests/table/table.txt
@@ -9,13 +9,13 @@
# - Columns with missing information
# - Some blank values different from the internal blank values.
-# Column 10: DOUBLE [no units, d] Column with double values
+# Column 10: DOUBLE [no units, d, 255] Column with double values
-# Column 1: UCHAR_DATA [no units, uc, 255] Column with unsigned char values
-# Column 2: [no-units, c, -5] Column with char values
+# Column 1: UCHAR_DATA [no units, uc, 5] Column with unsigned char values
+# Column 2: CHAR [no-units, c] Column with char values
# Column 3: STRING data [, str21, no data] Column with string values
# Column 4: USHORT data [,us] Column with unsigned short values
-# Column 5: [no units, s] Column with short values
+# Column 5: SHORT [no units, s] Column with short values
# Column 7: LONG [no units, l] Column with long values
# Column 8: LONGLONG [no units, L] Column with LONGLONG values
# Column 9: FLOAT [no units, f,-99] Column with float values
@@ -23,17 +23,24 @@
# Column 6: UINT [,ui]
+# IMPORTANT NOTE FOR FITS ASCII tables: CFITSIO will give its error
+# 412 (data type conversion overflow) when the number cannot be
+# printed in the provided space (with full precision). So make sure
+# that the full-integer part of the number has less characters than
+# the `width - precision - 1' (when everything is default, you can get
+# these values from `lib/gnuastro/table.h').
-1 -1 The vertical lines 3455 -3455 1 -1 9 2.3e4
8.39133434352355
-2 -2 are only for easy 3466 -3466 2 -2 10 2300
893.3497e50
-3 -3 identification of the 3467 -3467 3 -3 12 2.4
93487.3473234343
-4 -4 limits of this string 3468 -3468 4 -4 800 894.83 8.2e8
-5 -5 |column. Characters | 3469 -3469 5 -5 8923 99.232
-7.3238473343e4
-6 -6 |beyond this will be| 20821 -20821 6 -6 9823 8874.2
769387424234234
-7 -7 read as a number. 20822 -20822 7 -7 7232 1E10
8.3343e-5
-8 -8 no data 20823 -20823 8 -8 921 -8.4e2
934892734.82
-9 -9 address@hidden@ 60983 -25722 9 -9 8127 -99.0
3474924.489252
-10 -10 Characters%^&*()~ 62182 -30100 10 -10 8287 7.3e-9
-3467.3432e10
-11 -127 no data 65500 -32700 11 -11 999 8.73e2
897234.34897
-255 -12 -- Last Line :-) -- 65501 -32701 12 -12 8282 892.23
89750298.3653
+
+1 -1 The vertical lines 3455 -3455 1 -1 9 1874.103872
8.391334343995 1
+2 -2 are only for easy 3466 -3466 2 -2 10 123.93373
893.3497e5 2
+3 -3 visual identification 3467 -3467 3 -3 12 -0.737648 nan
3
+4 -4 of the limits of this 3468 -3468 4 -4 800 78.983
8.2328438e8 4
+5 -5 |string column. | 3469 -3469 5 -5 8923 -99
-7.32384e4 5
+6 -6 |characters beyond | 20821 -20821 6 -6 9823 -99 nan
6
+7 -7 the last one will be 20822 -20822 7 -7 7232 9999
8.3343e-5 7
+8 -8 read as a number. 20823 -20823 8 -8 921 2.3
934892734.82 8
+9 -9 address@hidden@ 60983 -25722 9 -9 8127 -99
3474924.489252 9
+10 -10 Characters%^&*()~ 62182 -30100 10 -10 8287 7.3e-4
-3467.3432e5 10
+11 -12 no data 65500 -32700 11 -11 999 8.73E2 nan
11
+255 -12 -- Last Line :-) -- 65501 -32701 12 -12 8282 892.23
8975.3653 12
diff --git a/tests/table/txt-to-fits-ascii.sh b/tests/table/txt-to-fits-ascii.sh
new file mode 100755
index 0000000..8d69c8c
--- /dev/null
+++ b/tests/table/txt-to-fits-ascii.sh
@@ -0,0 +1,51 @@
+# Convert an ASCII table to a binary table
+#
+# See the Tests subsection of the manual for a complete explanation
+# (in the Installing gnuastro section).
+#
+# Original author:
+# Mohammad Akhlaghi <address@hidden>
+# Contributing author(s):
+#
+# Copying and distribution of this file, with or without modification,
+# are permitted in any medium without royalty provided the copyright
+# notice and this notice are preserved. This file is offered as-is,
+# without any warranty.
+
+
+
+
+
+# Preliminaries
+# =============
+#
+# Set the variabels (The executable is in the build tree). Do the
+# basic checks to see if the executable is made or if the defaults
+# file exists (basicchecks.sh is in the source tree).
+prog=table
+execname=../bin/$prog/ast$prog
+table=$topsrc/tests/$prog/table.txt
+
+
+
+
+
+# Skip?
+# =====
+#
+# If the dependencies of the test don't exist, then skip it. There are two
+# types of dependencies:
+#
+# - The executable was not made (for example due to a configure option),
+#
+# - The input data was not made (for example the test that created the
+# data file failed).
+if [ ! -f $execname ] || [ ! -f $img ]; then exit 77; fi
+
+
+
+
+
+# Actual test script
+# ==================
+$execname $table --output=ascii-table.fits --tabletype=fits-ascii
- [gnuastro-commits] master 6d68470 033/125: Column info format for writing ASCII tables, (continued)
- [gnuastro-commits] master 6d68470 033/125: Column info format for writing ASCII tables, Mohammad Akhlaghi, 2017/04/23
- [gnuastro-commits] master 0fd75fe 040/125: With no columns, Table program will print all columns, Mohammad Akhlaghi, 2017/04/23
- [gnuastro-commits] master 8090e6d 038/125: Corrections to FITS table reading, Mohammad Akhlaghi, 2017/04/23
- [gnuastro-commits] master 1156793 035/125: ASCII table information fully ready for selection, Mohammad Akhlaghi, 2017/04/23
- [gnuastro-commits] master 3c7773f 037/125: Table library prints ASCII columns with blanks, Mohammad Akhlaghi, 2017/04/23
- [gnuastro-commits] master 1dca684 047/125: Minor corrections to Gnuastro plain text table format, Mohammad Akhlaghi, 2017/04/23
- [gnuastro-commits] master 620146e 028/125: Library function for writing columns to txt file, Mohammad Akhlaghi, 2017/04/23
- [gnuastro-commits] master 9ec7556 039/125: Table's output file type set common sense, Mohammad Akhlaghi, 2017/04/23
- [gnuastro-commits] master de80e97 046/125: Further explanations on Gnuastro's plain text tables, Mohammad Akhlaghi, 2017/04/23
- [gnuastro-commits] master a5a7c45 048/125: Correction in Gnuastro text table format, Mohammad Akhlaghi, 2017/04/23
- [gnuastro-commits] master 7b33afa 043/125: FITS ascii and binary table I/O done with tests,
Mohammad Akhlaghi <=
- [gnuastro-commits] master beeb995 055/125: Corrected options added for make check, Mohammad Akhlaghi, 2017/04/23
- [gnuastro-commits] master 0a1036f 025/125: Data structure with name, units, comments and status, Mohammad Akhlaghi, 2017/04/23
- [gnuastro-commits] master e5373e0 034/125: Column info read from comments in ASCII tables, Mohammad Akhlaghi, 2017/04/23
- [gnuastro-commits] master e8ddf69 058/125: Option description correction in mkprof, Mohammad Akhlaghi, 2017/04/23
- [gnuastro-commits] master 9bb47f3 051/125: New elements for argp_option for new option management, Mohammad Akhlaghi, 2017/04/23
- [gnuastro-commits] master 185cafa 045/125: Output type for binary arithmetic corrected, Mohammad Akhlaghi, 2017/04/23
- [gnuastro-commits] master c59d66c 064/125: tmpfs-config-make now has the programs that can be built, Mohammad Akhlaghi, 2017/04/23
- [gnuastro-commits] master 23a541a 056/125: Single correction of string keyword values in FITS tables, Mohammad Akhlaghi, 2017/04/23
- [gnuastro-commits] master 4c28d13 042/125: Problem in reading blank FITS ASCII table fixed, Mohammad Akhlaghi, 2017/04/23
- [gnuastro-commits] master 08927b8 044/125: New Table formats section in manual, Mohammad Akhlaghi, 2017/04/23