Changeset 32229
- Timestamp:
- Aug 30, 2011, 3:50:05 PM (15 years ago)
- File:
-
- 1 edited
-
trunk/psLib/src/fits/psFitsTableNew.c (modified) (8 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/psLib/src/fits/psFitsTableNew.c
r32228 r32229 7 7 * @author Bill Sweeney IfA 8 8 * 9 * @version $Revision: 1.33 $ $Name: not supported by cvs2svn $10 * @date $Date: 2008-07-04 03:18:06 $11 9 * 12 * Copyright 20 04-2005 Maui High Performance Computing Center, University of Hawaii10 * Copyright 2011 Institute for Astronomy, University of Hawaii 13 11 */ 14 12 … … 33 31 #include "psAssert.h" 34 32 35 #define MAX_STRING_LENGTH 256 // maximum length string for FITS routines33 // #define MAX_STRING_LENGTH 256 // maximum length string for FITS routines 36 34 37 35 … … 443 441 } 444 442 445 #ifdef notdef446 // Find the unique items in the array of metadata 'rows', and their sizes447 psMetadata *colSpecs = psMetadataAlloc(); // Column specifications448 size_t rowSize = 0; // Size (in bytes) of each row449 for (long i = 0; i < numRows; i++) {450 psMetadata* row = table->data[i];451 452 if (!row) {453 continue;454 }455 psMetadataIterator *rowIter = psMetadataIteratorAlloc(row, PS_LIST_HEAD, NULL); // Iterator456 psMetadataItem *colItem; // Column item, from iteration457 while ((colItem = psMetadataGetAndIncrement(rowIter))) {458 if (!(PS_DATA_IS_PRIMITIVE(colItem->type) || colItem->type == PS_DATA_STRING ||459 colItem->type == PS_DATA_VECTOR)) {460 // unsupported type -- treating as an error461 psError(PS_ERR_BAD_PARAMETER_TYPE, true,462 "Unsupported data type (%d) for Metadata Item '%s' in row %ld.",463 colItem->type, colItem->name, i);464 psFree(rowIter);465 psFree(colSpecs);466 return false;467 }468 469 size_t size = columnSize(colItem); // Size for this column470 471 // Check to see if we know about this one; or update the size if required472 psMetadataItem *colSpecItem = psMetadataLookup(colSpecs, colItem->name);473 if (!colSpecItem) {474 // A new one!475 colSpec *spec = psAlloc(sizeof(colSpec)); // Specification for this column476 // BOOL type is not a valid vector type, so we translate it to U8477 spec->type = colItem->type == PS_TYPE_BOOL ? PS_TYPE_U8 : colItem->type;478 spec->size = size;479 if (colItem->type == PS_DATA_VECTOR) {480 psVector *vector = colItem->data.V; // The vector481 spec->vectorType = vector->type.type;482 }483 psMetadataAddPtr(colSpecs, PS_LIST_TAIL, colItem->name, PS_DATA_UNKNOWN, "", spec);484 psFree(spec); // Drop reference485 rowSize += PSELEMTYPE_SIZEOF(spec->type);486 } else {487 colSpec *spec = colSpecItem->data.V; // The specification488 if (size > spec->size) {489 spec->size = size;490 }491 if (colItem->type != spec->type &&492 colItem->type != PS_TYPE_BOOL && spec->type != PS_TYPE_U8) {493 psWarning("Differing type found for column %s: %x vs %x --- using the first found.\n",494 colSpecItem->name, colItem->type, spec->type);495 }496 if (colItem->type == PS_DATA_VECTOR) {497 psVector *vector = colItem->data.V; // The vector498 if (vector->type.type != spec->vectorType) {499 psWarning("Differing vector type found for column %s: %x vs %x "500 "--- using the first found.\n", colSpecItem->name, vector->type.type,501 spec->vectorType);502 }503 }504 }505 }506 psFree(rowIter);507 }508 509 long numColumns = colSpecs->list->n;// Number of columns510 if (numColumns == 0) {511 // No table columns found512 psError(PS_ERR_BAD_PARAMETER_SIZE, true,513 "Did not find any column data to write to a table.");514 psFree(colSpecs);515 return false;516 }517 #endif // notdef end of OLD column spec determination518 519 443 // Create array of column names and types. 520 444 psArray *columnNames = psArrayAlloc(table->numCols); // Array of column names, for cfitsio … … 597 521 // colSpec *spec = colSpecItem->data.V; // The specification 598 522 if (PS_DATA_IS_PRIMITIVE(column->type)) { 599 #ifdef notdef600 size_t dataSize = PSELEMTYPE_SIZEOF(column->type); // Size (in bytes) of this type601 psVector *columnData = psVectorAlloc(table->n, column->type); // The raw row data, to be written602 psVectorInit(columnData, 0);603 for (long i = 0; i < table->numRows; i++) {604 psMetadata *row = table->data[i]; // The row of interest605 psMetadataItem *dataItem = psMetadataLookup(row, colSpecItem->name); // Value of interest606 if (dataItem) {607 memcpy(&columnData->data.U8[i * dataSize], &dataItem->data, dataSize);608 } else {609 // this element is missing from this row; insert an appropriate-sized place holder610 // XXX this should insert a NAN for float / double and an appropriate blank for int types611 // XXX for the moment I am putting in 0.0612 memset(&columnData->data.U8[i * dataSize], 0, dataSize);613 }614 }615 #endif616 617 523 int fitsDataType; // Data type for cfitsio 618 524 p_psFitsTypeToCfitsio(column->type, NULL, NULL, &fitsDataType); … … 629 535 switch (column->type) { 630 536 case PS_DATA_STRING: { 631 #ifdef notdef632 psArray *strings = psArrayAlloc(table->n); // Array of strings633 for (long i = 0; i < table->n; i++) {634 psMetadata *row = table->data[i]; // The row of interest635 strings->data[i] = psMemIncrRefCounter(psMetadataLookupStr(NULL, row,636 colSpecItem->name));637 }638 fits_write_col_str(fits->fd, colNum, 1, 1, table->n, (char**)strings->data, &status);639 #endif640 537 fits_write_col_str(fits->fd, colNum, 1, 1, table->numRows, (char**)column->data.str, &status); 641 538 // psFree(strings); … … 647 544 psVectorInit(columnData, 0); 648 545 for (long i = 0; i < table->numRows; i++) { 649 #ifdef notdef650 psMetadata *row = table->data[i]; // The row of interest651 psMetadataItem* dataItem = psMetadataLookup(row, colSpecItem->name);652 if (dataItem->type != PS_DATA_VECTOR) {653 // Just in case --- get a zero instead of some weird result654 continue;655 }656 psVector *vector = dataItem->data.V;657 #endif658 546 psVector *vector = column->data.vec[i]; 659 547 memcpy(&columnData->data.U8[i * dataSize * column->elementSize], vector->data.U8, … … 692 580 } 693 581 694 // END OF new insert table695 696 582 bool psFitsWriteTableNew(psFits* fits, 697 583 const psMetadata* header, … … 708 594 return fitsInsertTableNew(fits, header, table, extname, true, writeData); 709 595 } 710 711 #ifdef notdef712 713 psArray* psFitsReadTableColumn(const psFits* fits,714 const char* colname)715 {716 PS_ASSERT_FITS_NON_NULL(fits, NULL);717 PS_ASSERT_STRING_NON_EMPTY(colname, NULL);718 719 if (!readTableCheck(fits)) {720 if (emptyTableCheck(fits)) {721 return psArrayAlloc(0);722 }723 psError(PS_ERR_BAD_FITS, true, "Extension is not a table");724 return NULL;725 }726 727 int colnum = 0;728 int status = 0;729 730 // find the column by name731 if (fits_get_colnum(fits->fd, CASESEN, (char*)colname, &colnum, &status) != 0) {732 psFitsError(status, true, "Specified column, %s, was not found.", colname);733 return NULL;734 }735 736 // get the number of rows737 long numRows = psFitsTableSize(fits);738 if (numRows == -1) {739 return NULL;740 }741 742 // get the column length.743 int width;744 if (fits_get_col_display_width(fits->fd, colnum, &width, &status) != 0) {745 psFitsError(status, true, "Could not determine the datatype of the table column.");746 return NULL;747 }748 749 // allocate the buffers750 psArray* result = psArrayAlloc(numRows);751 for (int row = 0; row < numRows; row++) {752 result->data[row] = psStringAlloc(width);753 }754 755 fits_read_col_str(fits->fd, colnum, 1, 1, numRows, "", (char**)result->data, NULL, &status);756 if (psFitsError(status, true, "Failed to read table column.")) {757 psFree(result);758 return NULL;759 }760 761 return result;762 }763 764 psVector* psFitsReadTableColumnNum(const psFits* fits,765 const char* colname)766 {767 PS_ASSERT_FITS_NON_NULL(fits, NULL);768 PS_ASSERT_STRING_NON_EMPTY(colname, NULL);769 770 if (!readTableCheck(fits)) {771 psError(PS_ERR_BAD_FITS, true, "Extension is not a table");772 return NULL;773 }774 775 int status = 0;776 int colnum = 0;777 778 // find the column by name779 if (fits_get_colnum(fits->fd, CASESEN, (char*)colname, &colnum, &status) != 0) {780 psFitsError(status, true, "Specified column, %s, was not found.", colname);781 return NULL;782 }783 784 // get the number of rows785 long numRows = psFitsTableSize(fits);786 if (numRows == -1) {787 return NULL;788 }789 790 // get the column datatype.791 int typecode;792 long repeat;793 long width;794 if (fits_get_eqcoltype(fits->fd, colnum, &typecode, &repeat, &width, &status) != 0) {795 psFitsError(status, true, "Could not determine the datatype of the table column.");796 return NULL;797 }798 799 psVector* result = psVectorAlloc(numRows, p_psFitsTypeFromCfitsio(typecode));800 801 fits_read_col(fits->fd, typecode, colnum, 1, 1, numRows, NULL, (psPtr)(result->data.U8), NULL, &status);802 if (psFitsError(status, true, "Failed to read table column.")) {803 psFree(result);804 return NULL;805 }806 807 return result;808 }809 810 811 psArray* psFitsReadTable(const psFits* fits)812 {813 PS_ASSERT_FITS_NON_NULL(fits, NULL);814 815 if (!readTableCheck(fits)) {816 if (emptyTableCheck(fits)) {817 return psArrayAlloc(0);818 }819 psError(PS_ERR_BAD_FITS, true, "Extension is not a table");820 return NULL;821 }822 823 // get the number of rows824 long numRows = psFitsTableSize(fits);825 if (numRows == -1) {826 return NULL;827 }828 829 psArray* table = psArrayAlloc(numRows);830 831 for (int row = 0; row < numRows; row++) {832 psTrace("psLib.fits",5,"Reading row %i of %li\n", row, numRows);833 table->data[row] = psFitsReadTableRow(fits,row);834 }835 836 return table;837 }838 839 bool psFitsWriteTable(psFits* fits,840 const psMetadata* header,841 const psArray* table,842 const char *extname)843 {844 PS_ASSERT_FITS_NON_NULL(fits, false);845 PS_ASSERT_FITS_WRITABLE(fits, false);846 if (!psFitsMoveLast(fits)) {847 psError(PS_ERR_UNKNOWN, false, "Unable to move to last extension to write table");848 return false;849 }850 return psFitsInsertTable(fits, header, table, extname, true);851 }852 853 854 // Return the size of the column855 static inline size_t columnSize(const psMetadataItem *item // Item for which to get the size856 )857 {858 if (PS_DATA_IS_PRIMITIVE(item->type)) {859 return 1;860 }861 switch (item->type) {862 case PS_DATA_STRING:863 return strlen(item->data.V);864 case PS_DATA_VECTOR: {865 psVector *vector = item->data.V;866 return vector ? vector->n : 0;867 }868 default:869 psAbort("Shouldn't ever get here.");870 }871 return 0;872 }873 874 // Get the TFORM character, given a PS type875 static inline char getTForm(psDataType type)876 {877 switch (type) {878 case PS_TYPE_U8:879 case PS_TYPE_S8:880 return 'B';881 case PS_TYPE_S16:882 return 'I';883 case PS_TYPE_S32:884 return 'J';885 case PS_TYPE_U64:886 case PS_TYPE_S64:887 return 'K';888 case PS_TYPE_U16:889 return 'U';890 case PS_TYPE_U32:891 return 'V';892 case PS_TYPE_F32:893 return 'E';894 case PS_TYPE_F64:895 return 'D';896 case PS_TYPE_BOOL:897 return 'L';898 case PS_DATA_STRING:899 return 'A';900 default:901 psError(PS_ERR_UNKNOWN, true, "Unknown type: %x\n", type);902 return '?';903 }904 }905 906 907 // Column specification908 // Included here, because there's no need for the user to have access to it909 typedef struct {910 psDataType type; // psLib type (e.g., PS_DATA_STRING or PS_TYPE_F32)911 size_t size; // Size (number of repeats)912 psElemType vectorType; // psLib type of vectors913 } colSpec;914 915 916 static bool fitsInsertTable(psFits* fits, // FITS file917 const psMetadata* header, // FITS header to write918 const psArray* table, // Table to write919 const char *extname, // Extension name to give table920 bool after, // Write table after current extension?921 bool writeData // Write data?922 )923 {924 PS_ASSERT_FITS_NON_NULL(fits, false);925 PS_ASSERT_FITS_WRITABLE(fits, false);926 PS_ASSERT_ARRAY_NON_NULL(table, false);927 928 int status = 0;929 930 long numRows = table->n;931 if (writeData && numRows < 1) {932 // no table data, what can I do?933 psError(PS_ERR_BAD_PARAMETER_SIZE, true,934 _("Can't create a table without any rows."));935 return false;936 }937 938 // Find the unique items in the array of metadata 'rows', and their sizes939 psMetadata *colSpecs = psMetadataAlloc(); // Column specifications940 size_t rowSize = 0; // Size (in bytes) of each row941 for (long i = 0; i < numRows; i++) {942 psMetadata* row = table->data[i];943 if (!row) {944 continue;945 }946 psMetadataIterator *rowIter = psMetadataIteratorAlloc(row, PS_LIST_HEAD, NULL); // Iterator947 psMetadataItem *colItem; // Column item, from iteration948 while ((colItem = psMetadataGetAndIncrement(rowIter))) {949 if (!(PS_DATA_IS_PRIMITIVE(colItem->type) || colItem->type == PS_DATA_STRING ||950 colItem->type == PS_DATA_VECTOR)) {951 // unsupported type -- treating as an error952 psError(PS_ERR_BAD_PARAMETER_TYPE, true,953 "Unsupported data type (%d) for Metadata Item '%s' in row %ld.",954 colItem->type, colItem->name, i);955 psFree(rowIter);956 psFree(colSpecs);957 return false;958 }959 960 size_t size = columnSize(colItem); // Size for this column961 962 // Check to see if we know about this one; or update the size if required963 psMetadataItem *colSpecItem = psMetadataLookup(colSpecs, colItem->name);964 if (!colSpecItem) {965 // A new one!966 colSpec *spec = psAlloc(sizeof(colSpec)); // Specification for this column967 // BOOL type is not a valid vector type, so we translate it to U8968 spec->type = colItem->type == PS_TYPE_BOOL ? PS_TYPE_U8 : colItem->type;969 spec->size = size;970 if (colItem->type == PS_DATA_VECTOR) {971 psVector *vector = colItem->data.V; // The vector972 spec->vectorType = vector->type.type;973 }974 psMetadataAddPtr(colSpecs, PS_LIST_TAIL, colItem->name, PS_DATA_UNKNOWN, "", spec);975 psFree(spec); // Drop reference976 rowSize += PSELEMTYPE_SIZEOF(spec->type);977 } else {978 colSpec *spec = colSpecItem->data.V; // The specification979 if (size > spec->size) {980 spec->size = size;981 }982 if (colItem->type != spec->type &&983 colItem->type != PS_TYPE_BOOL && spec->type != PS_TYPE_U8) {984 psWarning("Differing type found for column %s: %x vs %x --- using the first found.\n",985 colSpecItem->name, colItem->type, spec->type);986 }987 if (colItem->type == PS_DATA_VECTOR) {988 psVector *vector = colItem->data.V; // The vector989 if (vector->type.type != spec->vectorType) {990 psWarning("Differing vector type found for column %s: %x vs %x "991 "--- using the first found.\n", colSpecItem->name, vector->type.type,992 spec->vectorType);993 }994 }995 }996 }997 psFree(rowIter);998 }999 1000 long numColumns = colSpecs->list->n;// Number of columns1001 if (numColumns == 0) {1002 // No table columns found1003 psError(PS_ERR_BAD_PARAMETER_SIZE, true,1004 "Did not find any column data to write to a table.");1005 psFree(colSpecs);1006 return false;1007 }1008 1009 // Create array of column names and types.1010 psArray *columnNames = psArrayAlloc(numColumns); // Array of column names, for cfitsio1011 psArray *columnTypes = psArrayAlloc(numColumns); // Array of column types, for cfitsio1012 psMetadataIterator *colSpecsIter = psMetadataIteratorAlloc(colSpecs, PS_LIST_HEAD, NULL); // Iterator1013 psMetadataItem *colSpecItem; // Column specification item, from iteration1014 for (long i = 0; (colSpecItem = psMetadataGetAndIncrement(colSpecsIter)); i++) {1015 colSpec *spec = colSpecItem->data.V; // The specification1016 columnNames->data[i] = psMemIncrRefCounter(colSpecItem->name);1017 psString colType = NULL; // The column type1018 if (spec->type == PS_DATA_VECTOR) {1019 psStringAppend(&colType, "%zd%c", spec->size, getTForm(spec->vectorType));1020 } else {1021 psStringAppend(&colType, "%zd%c", spec->size, getTForm(spec->type));1022 }1023 columnTypes->data[i] = colType;1024 }1025 1026 // Create the table HDU1027 int numHDUs = psFitsGetSize(fits); // Number of HDUs in file1028 if (numHDUs == 0) {1029 // We're creating the first extension1030 fits_create_tbl(fits->fd,1031 BINARY_TBL,1032 writeData ? numRows : 0, // number of rows in table1033 numColumns, // number of columns in table1034 (char**)columnNames->data, // names of the columns1035 (char**)columnTypes->data, // format of the columns1036 NULL, // physical unit of columns1037 NULL, // skip extension name: we set the by hand below1038 &status);1039 } else {1040 if (!after) {1041 if (psFitsGetExtNum(fits) == 0) {1042 // We're creating a replacement primary HDU.1043 // Set status to signal fits_insert_img to insert a new primary HDU1044 status = PREPEND_PRIMARY;1045 } else {1046 // Move back one to perform an insert after the previous HDU1047 psFitsMoveExtNum(fits, -1, true);1048 }1049 }1050 // Insert the table1051 fits_insert_btbl(fits->fd,1052 writeData ? numRows : 0, // number of rows in table1053 numColumns, // number of columns in table1054 (char**)columnNames->data, // names of the columns1055 (char**)columnTypes->data, // format of the columns1056 NULL, // physical unit of columns1057 NULL, // skip extension name: we set this by hand below1058 0, &status);1059 }1060 psFree(columnNames);1061 psFree(columnTypes);1062 1063 if (status != 0) {1064 psFitsError(status, true, "Unable to create FITS table with %ld columns and %ld rows",1065 numColumns, table->n);1066 psFree(colSpecsIter);1067 psFree(colSpecs);1068 return false;1069 }1070 1071 // Write header1072 if (header && !psFitsWriteHeader(fits, header)) {1073 psError(PS_ERR_IO, false, "Unable to write FITS header.\n");1074 psFree(colSpecsIter);1075 psFree(colSpecs);1076 return false;1077 }1078 1079 // write the header, if any.1080 if (extname && strlen(extname) > 0) {1081 if (!psFitsSetExtName(fits, extname)) {1082 psError(PS_ERR_IO, false, "Unable to write FITS header extension name.\n");1083 psFree(colSpecsIter);1084 psFree(colSpecs);1085 return false;1086 }1087 }1088 1089 // cfitsio requires that we write the data by columns --- urgh!1090 if (writeData) {1091 psMetadataIteratorSet(colSpecsIter, PS_LIST_HEAD);1092 for (long colNum = 1; (colSpecItem = psMetadataGetAndIncrement(colSpecsIter)); colNum++) {1093 // Note: colNum is unit-indexed, because it's for cfitsio1094 colSpec *spec = colSpecItem->data.V; // The specification1095 if (PS_DATA_IS_PRIMITIVE(spec->type)) {1096 size_t dataSize = PSELEMTYPE_SIZEOF(spec->type); // Size (in bytes) of this type1097 psVector *columnData = psVectorAlloc(table->n, spec->type); // The raw row data, to be written1098 psVectorInit(columnData, 0);1099 for (long i = 0; i < table->n; i++) {1100 psMetadata *row = table->data[i]; // The row of interest1101 psMetadataItem *dataItem = psMetadataLookup(row, colSpecItem->name); // Value of interest1102 if (dataItem) {1103 memcpy(&columnData->data.U8[i * dataSize], &dataItem->data, dataSize);1104 } else {1105 // this element is missing from this row; insert an appropriate-sized place holder1106 // XXX this should insert a NAN for float / double and an appropriate blank for int types1107 // XXX for the moment I am putting in 0.01108 memset(&columnData->data.U8[i * dataSize], 0, dataSize);1109 }1110 }1111 1112 int fitsDataType; // Data type for cfitsio1113 p_psFitsTypeToCfitsio(spec->type, NULL, NULL, &fitsDataType);1114 fits_write_col(fits->fd,1115 fitsDataType,1116 colNum, // column number1117 1, // first row1118 1, // first element1119 table->n, // number of rows1120 columnData->data.U8, // the data1121 &status);1122 psFree(columnData);1123 } else {1124 switch (spec->type) {1125 case PS_DATA_STRING: {1126 psArray *strings = psArrayAlloc(table->n); // Array of strings1127 for (long i = 0; i < table->n; i++) {1128 psMetadata *row = table->data[i]; // The row of interest1129 strings->data[i] = psMemIncrRefCounter(psMetadataLookupStr(NULL, row,1130 colSpecItem->name));1131 }1132 fits_write_col_str(fits->fd, colNum, 1, 1, table->n, (char**)strings->data, &status);1133 psFree(strings);1134 break;1135 }1136 case PS_DATA_VECTOR: {1137 size_t dataSize = PSELEMTYPE_SIZEOF(spec->vectorType); // Size of data, in bytes1138 psVector *columnData = psVectorAlloc(spec->size * table->n * dataSize, PS_TYPE_U8);1139 psVectorInit(columnData, 0);1140 for (long i = 0; i < table->n; i++) {1141 psMetadata *row = table->data[i]; // The row of interest1142 psMetadataItem* dataItem = psMetadataLookup(row, colSpecItem->name);1143 if (dataItem->type != PS_DATA_VECTOR) {1144 // Just in case --- get a zero instead of some weird result1145 continue;1146 }1147 psVector *vector = dataItem->data.V;1148 memcpy(&columnData->data.U8[i * dataSize * spec->size], vector->data.U8,1149 vector->n * dataSize);1150 }1151 1152 int fitsDataType; // Data type for cfitsio1153 p_psFitsTypeToCfitsio(spec->vectorType, NULL, NULL, &fitsDataType);1154 fits_write_col(fits->fd, fitsDataType, colNum, 1, 1, table->n * spec->size,1155 columnData->data.U8, &status);1156 psFree(columnData);1157 break;1158 }1159 default:1160 psAbort("Should never get here.\n");1161 }1162 }1163 1164 // Check error status from writing column1165 if (status != 0) {1166 psFitsError(status, true, "Unable to write column %ld of FITS table", colNum);1167 psFree(colSpecsIter);1168 psFree(colSpecs);1169 return false;1170 }1171 }1172 }1173 1174 psFree(colSpecsIter);1175 psFree(colSpecs);1176 1177 // This forces a re-scan of the header to ensure everything's kosher. We found this occassionally1178 // necessary for compressed images, which are tables, so perhaps it helps here too. I guess it can't1179 // hurt.1180 ffrdef(fits->fd, &status);1181 if (psFitsError(status, true, "Could not re-scan HDU.")) {1182 return false;1183 }1184 1185 return true;1186 }1187 1188 1189 bool psFitsInsertTable(psFits* fits, const psMetadata* header, const psArray* table, const char *extname,1190 bool after)1191 {1192 PS_ASSERT_FITS_NON_NULL(fits, false);1193 PS_ASSERT_FITS_WRITABLE(fits, false);1194 return fitsInsertTable(fits, header, table, extname, after, true);1195 }1196 1197 bool psFitsWriteTableEmpty(psFits *fits, const psMetadata *header, const psMetadata *columns,1198 const char *extname)1199 {1200 PS_ASSERT_FITS_NON_NULL(fits, false);1201 PS_ASSERT_FITS_WRITABLE(fits, false);1202 if (!psFitsMoveLast(fits)) {1203 psError(PS_ERR_UNKNOWN, false, "Unable to move to last extension to write table");1204 return false;1205 }1206 psArray *table = psArrayAlloc(1); // Dummy table carrying column definitions1207 table->data[0] = psMemIncrRefCounter((psPtr)columns); // Casting away const1208 bool status = fitsInsertTable(fits, header, table, extname, true, false); // Status of insertion1209 psFree(table);1210 return status;1211 }1212 1213 bool psFitsInsertTableEmpty(psFits *fits, const psMetadata *header, const psMetadata *columns,1214 const char *extname, bool after)1215 {1216 PS_ASSERT_FITS_NON_NULL(fits, false);1217 PS_ASSERT_FITS_WRITABLE(fits, false);1218 psArray *table = psArrayAlloc(1); // Dummy table carrying column definitions1219 table->data[0] = psMemIncrRefCounter((psPtr)columns); // Casting away const1220 bool status = fitsInsertTable(fits, header, table, extname, after, false); // Status of insertion1221 psFree(table);1222 return status;1223 }1224 1225 1226 bool psFitsUpdateTable(psFits* fits,1227 const psMetadata* data,1228 int row)1229 {1230 PS_ASSERT_FITS_NON_NULL(fits, false);1231 PS_ASSERT_FITS_WRITABLE(fits, false);1232 PS_ASSERT_METADATA_NON_NULL(data, false);1233 PS_ASSERT_INT_NONNEGATIVE(row, false);1234 1235 if (!readTableCheck(fits)) {1236 psError(PS_ERR_BAD_FITS, true, "Extension is not a table");1237 return NULL;1238 }1239 1240 int status = 0;1241 psMetadataIterator* iter = psMetadataIteratorAlloc((psPtr)data, PS_LIST_HEAD, NULL);1242 psMetadataItem* item;1243 while ( (item=psMetadataGetAndIncrement(iter)) != NULL) {1244 if (PS_DATA_IS_PRIMITIVE(item->type) ||1245 item->type == PS_DATA_BOOL ||1246 item->type == PS_DATA_STRING) {1247 // operating on primitive data type or string, i.e., not a complex object1248 int colnum = 0;1249 1250 if (fits_get_colnum(fits->fd, CASESEN, item->name, &colnum, &status) == 0) {1251 // cooresponding column found in table1252 int dataType;1253 p_psFitsTypeToCfitsio(item->type, NULL, NULL, &dataType);1254 1255 if (fits_write_col(fits->fd, dataType, colnum, row+1, 1, 1, &item->data, &status) != 0) {1256 psFitsError(status, true, "Could not write data to file.");1257 psFree(iter);1258 return false;1259 }1260 } else {1261 // the column was not found.1262 psWarning("No column with the name '%s' exists in the table.", item->name);1263 }1264 }1265 }1266 1267 psFree(iter);1268 1269 // This forces a re-scan of the header to ensure everything's kosher. We found this occassionally1270 // necessary for compressed images, which are tables, so perhaps it helps here too. I guess it can't1271 // hurt.1272 ffrdef(fits->fd, &status);1273 if (psFitsError(status, true, "Could not re-scan HDU.")) {1274 return false;1275 }1276 1277 return true;1278 }1279 1280 1281 psMetadata *psFitsReadTableAllColumns(const psFits *fits)1282 {1283 PS_ASSERT_FITS_NON_NULL(fits, NULL);1284 1285 if (!readTableCheck(fits)) {1286 if (emptyTableCheck(fits)) {1287 return psMetadataAlloc();1288 }1289 psError(PS_ERR_BAD_FITS, true, "Extension is not a table");1290 return NULL;1291 }1292 1293 int status = 0; // CFITSIO return status1294 1295 long numRows = 0; // Number of rows in table1296 int numCols = 0; // Number of columns in table1297 fits_get_num_rows(fits->fd, &numRows, &status);1298 fits_get_num_cols(fits->fd, &numCols, &status);1299 if (status) {1300 psFitsError(status, true, "Failed to determine the size of the current HDU table.");1301 return NULL;1302 }1303 1304 int hdutype; // Type of HDU: need to distinguish ASCII and binary tables1305 fits_get_hdu_type(fits->fd, &hdutype, &status);1306 if (status) {1307 psFitsError(status, true, "Could not determine the HDU type.");1308 return false;1309 }1310 1311 psMetadata *table = psMetadataAlloc(); // Table to return1312 for (int col = 1; col <= numCols; col++) { // Fortran indexing1313 char name[FLEN_VALUE]; // Column name1314 if (hdutype == BINARY_TBL) {1315 fits_get_bcolparms(fits->fd, col, name,1316 NULL, NULL, NULL, NULL, NULL, NULL, NULL, &status);1317 } else {1318 fits_get_acolparms(fits->fd, col, name,1319 NULL, NULL, NULL, NULL, NULL, NULL, NULL, &status);1320 }1321 1322 int cfitsioType = 0; // Column type from CFITSIO1323 long repeat; // Number of repeats1324 fits_get_eqcoltype(fits->fd, col, &cfitsioType, &repeat, NULL, &status);1325 if (status) {1326 psFitsError(status, true, "Could not determine the column data for %s", name);1327 psFree(table);1328 return false;1329 }1330 1331 psDataType pslibType = p_psFitsTypeFromCfitsio(cfitsioType); // Column type in psLib1332 if (pslibType == PS_DATA_STRING) {1333 // Strings1334 int width; // Width of strings1335 if (fits_get_col_display_width(fits->fd, col, &width, &status) != 0) {1336 psFitsError(status, true, "Could not determine the width of column %s", name);1337 psFree(table);1338 return NULL;1339 }1340 psArray *array = psArrayAlloc(numRows); // Array of strings from table1341 for (int i = 0; i < numRows; i++) {1342 array->data[i] = psStringAlloc(width);1343 }1344 fits_read_col_str(fits->fd, col, 1, 1, numRows, "", (char**)array->data, NULL, &status);1345 if (status) {1346 psFitsError(status, true, "Failed to read column %s", name);1347 psFree(array);1348 psFree(table);1349 return NULL;1350 }1351 if (!psMetadataAddArray(table, PS_LIST_TAIL, name, 0, NULL, array)) {1352 psError(PS_ERR_BAD_FITS, false, "Unable to add column %s to table", name);1353 psFree(array);1354 psFree(table);1355 return NULL;1356 }1357 psFree(array);1358 } else if (repeat == 1) {1359 // Single numbers1360 psVector* vector = psVectorAlloc(numRows, pslibType); // Vector from table1361 fits_read_col(fits->fd, cfitsioType, col, 1, 1, numRows, NULL,1362 vector->data.U8, NULL, &status);1363 if (status) {1364 psFitsError(status, true, "Failed to read column %s", name);1365 psFree(vector);1366 psFree(table);1367 return NULL;1368 }1369 if (!psMetadataAddVector(table, PS_LIST_TAIL, name, 0, NULL, vector)) {1370 psError(PS_ERR_BAD_FITS, false, "Unable to add column %s to table", name);1371 psFree(vector);1372 psFree(table);1373 return NULL;1374 }1375 psFree(vector);1376 } else {1377 // Vectors of numbers1378 psAssert(pslibType != PS_DATA_STRING, "Vectors of strings not handled");1379 psImage *image = psImageAlloc(repeat, numRows, pslibType); // Image to store vector of vectors1380 for (int row = 1, i = 0; row <= numRows; row++, i++) { // Fortran indexing for row1381 int anynul = 0; // Any nulls in what was read?1382 fits_read_col(fits->fd, cfitsioType, col, row, 1, repeat, NULL,1383 image->data.U8[i], &anynul, &status);1384 if (psFitsError(status, true, "Failed to read column %s row %d", name, row)) {1385 psFree(image);1386 psFree(table);1387 return NULL;1388 }1389 }1390 if (!psMetadataAddImage(table, PS_LIST_TAIL, name, 0, NULL, image)) {1391 psError(PS_ERR_BAD_FITS, false, "Unable to add column %s to table", name);1392 psFree(image);1393 psFree(table);1394 return NULL;1395 }1396 psFree(image);1397 }1398 }1399 1400 return table;1401 }1402 1403 bool psFitsWriteTableAllColumns(psFits *fits, psMetadata *header, const psMetadata *table, const char *extname)1404 {1405 PS_ASSERT_FITS_NON_NULL(fits, false);1406 PS_ASSERT_FITS_WRITABLE(fits, false);1407 PS_ASSERT_METADATA_NON_NULL(table, false);1408 1409 psArray *columns = psListToArray(table->list); // Columns in psMetadataItems1410 int numCols = columns->n; // Number of columns1411 long numRows = 0; // Number of rows1412 psArray *names = psArrayAlloc(numCols); // Column names1413 psArray *types = psArrayAlloc(numCols); // Column types1414 1415 for (int i = 0; i < numCols; i++) {1416 psMetadataItem *colItem = columns->data[i]; // Column1417 names->data[i] = psMemIncrRefCounter(colItem->name);1418 1419 size_t size = 0; // Size of column1420 char tform = 0; // Type in character for FITS1421 long rows = 0; // Number of rows1422 switch (colItem->type) {1423 case PS_DATA_VECTOR:1424 size = 1;1425 psVector *vector = colItem->data.V; // Vector of interest1426 tform = getTForm(vector->type.type);1427 rows = vector->n;1428 break;1429 case PS_DATA_ARRAY:1430 tform = getTForm(PS_DATA_STRING);1431 psArray *array = colItem->data.V; // Array of interest1432 rows = array->n;1433 for (int i = 0; i < rows; i++) {1434 const char *string = array->data[i];1435 size = PS_MAX(size, strlen(string));1436 }1437 break;1438 case PS_DATA_IMAGE: ;1439 psImage *image = colItem->data.V; // Image of interest1440 tform = getTForm(image->type.type);1441 size = image->numCols;1442 rows = image->numRows;1443 break;1444 default:1445 psAbort("Unrecognised column type: %x", colItem->type);1446 }1447 psString type = NULL; // Column type1448 psStringAppend(&type, "%zd%c", size, tform);1449 types->data[i] = type;1450 if (i == 0) {1451 numRows = rows;1452 } else if (numRows != rows) {1453 psError(PS_ERR_BAD_PARAMETER_SIZE, true, "Column %d has differing size: %ld vs %ld",1454 i, rows, numRows);1455 psFree(names);1456 psFree(types);1457 psFree(columns);1458 return false;1459 }1460 }1461 1462 // Create the table HDU1463 int numHDUs = psFitsGetSize(fits); // Number of HDUs in file1464 int status = 0; // Status from cfitsio1465 if (numHDUs == 0) {1466 // We're creating the first extension1467 fits_create_tbl(fits->fd, BINARY_TBL, numRows, numCols, (char**)names->data, (char**)types->data,1468 NULL, NULL, &status);1469 } else {1470 fits_insert_btbl(fits->fd, numRows, numCols, (char**)names->data, (char**)types->data,1471 NULL, NULL, 0, &status);1472 }1473 psFree(names);1474 psFree(types);1475 if (status) {1476 psFitsError(status, true, "Unable to create FITS table with %d columns and %ld rows",1477 numCols, numRows);1478 psFree(columns);1479 return false;1480 }1481 1482 // Write header1483 if (header && !psFitsWriteHeader(fits, header)) {1484 psError(psErrorCodeLast(), false, "Unable to write FITS header.\n");1485 psFree(columns);1486 return false;1487 }1488 if (extname && strlen(extname) > 0 && !psFitsSetExtName(fits, extname)) {1489 psError(psErrorCodeLast(), false, "Unable to write FITS header extension name.\n");1490 psFree(columns);1491 return false;1492 }1493 1494 // cfitsio requires that we write the data by columns --- urgh!1495 for (long col = 1, i = 0; col <= numCols; col++, i++) { // Fortran indexing1496 psMetadataItem *colItem = columns->data[i]; // Column1497 switch (colItem->type) {1498 case PS_DATA_VECTOR: {1499 psVector *vector = colItem->data.V; // Vector1500 int cfitsioType; // Data type for cfitsio1501 p_psFitsTypeToCfitsio(vector->type.type, NULL, NULL, &cfitsioType);1502 fits_write_col(fits->fd, cfitsioType, col, 1, 1, numRows, vector->data.U8, &status);1503 break;1504 }1505 case PS_DATA_ARRAY: {1506 psArray *array = colItem->data.V; // Array of strings1507 fits_write_col_str(fits->fd, col, 1, 1, numRows, (char**)array->data, &status);1508 break;1509 }1510 case PS_DATA_IMAGE: {1511 psImage *image = colItem->data.V; // Image of interest1512 psDataType type = image->type.type; // Type of data1513 psVector *vector = psVectorAlloc(image->numCols * image->numRows, type); // Vector from image1514 if (!p_psImageCopyToRawBuffer(vector->data.U8, image, type)) {1515 psError(psErrorCodeLast(), false, "Unable to copy image to buffer");1516 psFree(columns);1517 return false;1518 }1519 int cfitsioType; // Data type for cfitsio1520 p_psFitsTypeToCfitsio(type, NULL, NULL, &cfitsioType);1521 fits_write_col(fits->fd, cfitsioType, col, 1, 1, image->numRows * image->numCols,1522 vector->data.U8, &status);1523 break;1524 }1525 default:1526 psAbort("Unrecognised column type: %x", colItem->type);1527 }1528 // Check error status from writing column1529 if (status) {1530 psFitsError(status, true, "Unable to write column %ld of FITS table", col);1531 psFree(columns);1532 return false;1533 }1534 }1535 psFree(columns);1536 1537 // This forces a re-scan of the header to ensure everything's kosher. We found this occassionally1538 // necessary for compressed images, which are tables, so perhaps it helps here too. I guess it can't1539 // hurt.1540 ffrdef(fits->fd, &status);1541 if (status) {1542 psFitsError(status, true, "Could not re-scan HDU.");1543 return false;1544 }1545 1546 return true;1547 }1548 #endif // notdef
Note:
See TracChangeset
for help on using the changeset viewer.
