IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Changeset 32228


Ignore:
Timestamp:
Aug 30, 2011, 3:47:39 PM (15 years ago)
Author:
bills
Message:

working version of psFitsReadTableNew and psFitsWriteTableNew

Location:
trunk/psLib/src/fits
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/psLib/src/fits/Makefile.am

    r16185 r32228  
    99        psFitsImage.c \
    1010        psFitsTable.c \
     11        psFitsTableNew.c \
    1112        psFitsFloat.c \
    1213        psFitsFloatFile.c \
     
    2021        psFitsImage.h \
    2122        psFitsTable.h \
     23        psFitsTableNew.h \
    2224        psFitsFloat.h \
    2325        psFitsFloatFile.h \
  • trunk/psLib/src/fits/psFitsTableNew.c

    r32217 r32228  
    9696}
    9797
     98void breakhere()
     99{
     100}
     101
     102void
     103freeTable(psFitsTable *table) {
     104    for (int col = 0; col < table->numCols; col++) {
     105        psFitsTableColumn *column = &table->columns[col];
     106        psFree(column->name);
     107        // all of the members in the data union are pointers so just pick S32
     108        psFree(column->data.S32);
     109    }
     110    psFree(table->columns);
     111    psFree(table->index);
     112}
     113
     114psFitsTable* psFitsTableAlloc(int numCols, int numRows) {
     115    if (numCols <= 0) {
     116        psError(PS_ERR_BAD_PARAMETER_VALUE, true,
     117                "Can't allocate a psFitsTable with %d columns.", numCols);
     118        return NULL;
     119    }
     120
     121    psFitsTable *table = psAlloc(sizeof(psFitsTable));
     122    table->index = psMetadataAlloc();
     123    table->numRows = numRows;
     124    table->numCols = numCols;
     125    table->columns = psAlloc(sizeof(psFitsTableColumn) * numCols);
     126    memset(table->columns, sizeof(psFitsTableColumn) * numCols, 0);
     127    psMemSetDeallocator(table, (psFreeFunc) freeTable);
     128
     129    return table;
     130}
    98131
    99132psFitsTable* psFitsReadTableNew(const psFits* fits)
     
    122155
    123156    psTrace("psLib.fits",5,"Table size is %ix%li\n",numCols, numRows);
    124     // the row parameter in the proper range?
    125 #ifdef notdef
    126     if (row < 0 || row >= numRows) {
    127         psError(PS_ERR_BAD_PARAMETER_VALUE, true,
    128                 _("Specified row, %d, is not valid for current table of %ld rows."),
    129                 row, numRows);
    130         return NULL;
    131     }
    132 #endif
    133 
    134     psFitsTable *table = psAlloc(sizeof(psFitsTable));
    135     table->index = psMetadataAlloc(); \
    136     table->numRows = numRows;
    137     table->numCols = numCols;
    138     table->columns = psAlloc(sizeof(psFitsTableColumn) * numCols);
    139 //    psMetadata* data = psMetadataAlloc();
     157
     158    psFitsTable *table = psFitsTableAlloc(numCols, numRows);
    140159
    141160    int hdutype;                        // Type of HDU: need to distinguish ASCII and binary tables
     
    151170    for (int col = 1; col <= numCols; col++) {
    152171        // get the column name
     172        double tscal;
     173        double tzero;
    153174        if (hdutype == BINARY_TBL) {
    154175            fits_get_bcolparms(fits->fd, col, name,
    155                                NULL, NULL, NULL, NULL, NULL, NULL, NULL, &status);
     176                               NULL, NULL, NULL, &tscal, &tzero, NULL, NULL, &status);
    156177        } else {
    157178            fits_get_acolparms(fits->fd, col, name,
     
    170191                column->data.TYPE = psAlloc(sizeof(ps##TYPE)*table->numRows); \
    171192                if (repeat == 1) { \
     193                    column->elementSize = 1; \
    172194                    NATIVETYPE *values = (NATIVETYPE *) psAlloc(sizeof(NATIVETYPE) * table->numRows); \
    173195                    int anynul = 0; \
     196                    breakhere(); \
    174197                    fits_read_col(fits->fd, FITSTYPE, col, 1, \
    175198                                  1, numRows, NULL, values, &anynul, &status); \
     
    180203                            col, name, typecode, repeat); \
    181204                } else { \
     205                    column->elementSize = repeat; \
    182206                    column->type = PS_DATA_VECTOR; \
     207                    column->vectorType = PS_DATA_##TYPE; \
    183208                    column->data.vec = psAlloc(sizeof(psVector*) * table->numRows); \
    184209                    for (int row = 0; row < table->numRows; row++) { \
     
    192217                        } \
    193218                        column->data.vec[row] = vec; \
    194                         /* psMetadataAdd(data,PS_LIST_TAIL, name, PS_DATA_VECTOR, "", vec); */ \
    195219                        psFree(values); \
    196                         /* psFree(vec); */ \
    197220                    } \
    198221                    \
     
    201224            }
    202225
     226        // Handle cases where the data is "really" unsigned
     227        if (typecode == TLONG && tzero == 2147483648) {
     228            typecode = TULONG;
     229        } else if (typecode == TSHORT && tzero == 32768) {
     230            typecode = TUSHORT;
     231        }
     232
     233        // Save the column number for this column in the index metadata
    203234        psMetadataAddS32(table->index, PS_LIST_TAIL, name, 0, NULL, col-1);
     235
    204236        psFitsTableColumn *column = &table->columns[col-1];
    205         // column->name = psStringCopy(name);
     237        // This second copy of the name makes it easily available when writing the table
     238        column->name = psStringCopy(name);
    206239        switch (typecode) {
    207            // TBYTE and TSHORT fall though to read into psS32
    208           case TBYTE:
    209           case TSHORT:
     240            READ_TABLE_ROW_CASE(TBYTE, long, S32, S32);
     241            READ_TABLE_ROW_CASE(TSHORT, short, S16, S16);
     242            READ_TABLE_ROW_CASE(TUSHORT, unsigned short, U16, U16);
     243            READ_TABLE_ROW_CASE(TULONG, unsigned long, U32, U32);
    210244            READ_TABLE_ROW_CASE(TLONG, long, S32, S32);
    211245            READ_TABLE_ROW_CASE(TLONGLONG, psS64, S64, S64);
     
    216250              column->data.str = psAlloc(sizeof(psString) * table->numRows);
    217251              column->type = PS_DATA_STRING;
     252              column->elementSize = 0;
    218253              for (int row = 0; row < table->numRows; row++) {
    219254                  psString value = psStringAlloc(repeat);
     
    227262                  }
    228263                  column->data.str[row] = value;
     264                  int len = strlen(value);
     265                  if (len > column->elementSize) {
     266                    column->elementSize = len;
     267                  }
    229268              }
    230269              break;
     
    245284}
    246285
     286// return the index for a given column
    247287int psFitsTableGetColumnIndex(psFitsTable *table, psString name)
    248288{
     
    258298}
    259299
     300// return F32 value for given cell
    260301psF32 psFitsTableGetCellF32(psFitsTable *table, int row, int col) {
    261302    return table->columns[col].data.F32[row];
    262303}
    263304
     305// return value for a named column for a given row
    264306psF32 psFitsTableGetF32(bool *status, psFitsTable *table, psString name, int row) {
    265307    bool mdok;
     
    295337                    psFitsTableColumn *column = &table->columns[col];
    296338                    switch (column->type) {
     339                    case PS_DATA_S16:   
     340                        column->data.S16[newRow] = column->data.S16[row];
     341                        break;
     342                    case PS_DATA_U16:   
     343                        column->data.U16[newRow] = column->data.U16[row];
     344                        break;
    297345                    case PS_DATA_S32:   
    298346                        column->data.S32[newRow] = column->data.S32[row];
     347                        break;
     348                    case PS_DATA_U32:   
     349                        column->data.U32[newRow] = column->data.U32[row];
    299350                        break;
    300351                    case PS_DATA_S64:   
     
    331382        }
    332383    }
     384
    333385    // set the new number of rows
    334     // XXX: should we do this?
    335386    table->numRows = newRow;
    336387
     
    338389}
    339390
     391// Get the TFORM character, given a PS type
     392static inline char getTForm(psDataType type)
     393{
     394    switch (type) {
     395    case PS_TYPE_U8:
     396    case PS_TYPE_S8:
     397        return 'B';
     398    case PS_TYPE_S16:
     399        return 'I';
     400    case PS_TYPE_S32:
     401        return 'J';
     402    case PS_TYPE_U64:
     403    case PS_TYPE_S64:
     404        return 'K';
     405    case PS_TYPE_U16:
     406        return 'U';
     407    case PS_TYPE_U32:
     408        return 'V';
     409    case PS_TYPE_F32:
     410        return 'E';
     411    case PS_TYPE_F64:
     412        return 'D';
     413    case PS_TYPE_BOOL:
     414        return 'L';
     415    case PS_DATA_STRING:
     416        return 'A';
     417    default:
     418        psError(PS_ERR_UNKNOWN, true, "Unknown type: %x\n", type);
     419        return '?';
     420    }
     421}
     422
     423static bool fitsInsertTableNew(psFits* fits,          // FITS file
     424                            const psMetadata* header, // FITS header to write
     425                            psFitsTable *table,       // internal representation of the table
     426                            const char *extname,      // Extension name to give table
     427                            bool after,               // Write table after current extension?
     428                            bool writeData            // Write data?
     429                            )
     430{
     431    PS_ASSERT_FITS_NON_NULL(fits, false);
     432    PS_ASSERT_FITS_WRITABLE(fits, false);
     433    PS_ASSERT_PTR_NON_NULL(table, false);
     434
     435    int status = 0;
     436
     437    long numRows = table->numRows;
     438    if (writeData && numRows < 1) {
     439        // no table data, what can I do?
     440        psError(PS_ERR_BAD_PARAMETER_SIZE, true,
     441                _("Can't create a table without any rows."));
     442        return false;
     443    }
     444
    340445#ifdef notdef
    341 
     446    // Find the unique items in the array of metadata 'rows', and their sizes
     447    psMetadata *colSpecs = psMetadataAlloc(); // Column specifications
     448    size_t rowSize = 0;                 // Size (in bytes) of each row
     449    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); // Iterator
     456        psMetadataItem *colItem;        // Column item, from iteration
     457        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 error
     461                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 column
     470
     471            // Check to see if we know about this one; or update the size if required
     472            psMetadataItem *colSpecItem = psMetadataLookup(colSpecs, colItem->name);
     473            if (!colSpecItem) {
     474                // A new one!
     475                colSpec *spec = psAlloc(sizeof(colSpec)); // Specification for this column
     476                // BOOL type is not a valid vector type, so we translate it to U8
     477                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 vector
     481                    spec->vectorType = vector->type.type;
     482                }
     483                psMetadataAddPtr(colSpecs, PS_LIST_TAIL, colItem->name, PS_DATA_UNKNOWN, "", spec);
     484                psFree(spec);           // Drop reference
     485                rowSize += PSELEMTYPE_SIZEOF(spec->type);
     486            } else {
     487                colSpec *spec = colSpecItem->data.V; // The specification
     488                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 vector
     498                    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 columns
     510    if (numColumns == 0) {
     511        // No table columns found
     512        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 determination
     518
     519    // Create array of column names and types.
     520    psArray *columnNames = psArrayAlloc(table->numCols); // Array of column names, for cfitsio
     521    psArray *columnTypes = psArrayAlloc(table->numCols); // Array of column types, for cfitsio
     522    for (long i = 0; i < table->numCols; i++) {
     523        psFitsTableColumn *column = &table->columns[i];
     524        columnNames->data[i] = psMemIncrRefCounter(column->name);
     525        psString colType = NULL;        // The FITS column type
     526        size_t size = column->elementSize;
     527        if (column->type == PS_DATA_VECTOR) {
     528            psStringAppend(&colType, "%zd%c", size, getTForm(column->vectorType));
     529        } else {
     530            psStringAppend(&colType, "%zd%c", size, getTForm(column->type));
     531        }
     532        columnTypes->data[i] = colType;
     533    }
     534
     535    // Create the table HDU
     536    int numHDUs = psFitsGetSize(fits);  // Number of HDUs in file
     537    if (numHDUs == 0) {
     538        // We're creating the first extension
     539        fits_create_tbl(fits->fd,
     540                        BINARY_TBL,
     541                        writeData ? numRows : 0, // number of rows in table
     542                        table->numCols, // number of columns in table
     543                        (char**)columnNames->data, // names of the columns
     544                        (char**)columnTypes->data, // format of the columns
     545                        NULL, // physical unit of columns
     546                        NULL, // skip extension name: we set the by hand below
     547                        &status);
     548    } else {
     549        if (!after) {
     550            if (psFitsGetExtNum(fits) == 0) {
     551                // We're creating a replacement primary HDU.
     552                // Set status to signal fits_insert_img to insert a new primary HDU
     553                status = PREPEND_PRIMARY;
     554            } else {
     555                // Move back one to perform an insert after the previous HDU
     556                psFitsMoveExtNum(fits, -1, true);
     557            }
     558        }
     559        // Insert the table
     560        fits_insert_btbl(fits->fd,
     561                         writeData ? numRows : 0, // number of rows in table
     562                         table->numCols, // number of columns in table
     563                         (char**)columnNames->data, // names of the columns
     564                         (char**)columnTypes->data, // format of the columns
     565                         NULL, // physical unit of columns
     566                         NULL, // skip extension name: we set this by hand below
     567                         0, &status);
     568    }
     569    psFree(columnNames);
     570    psFree(columnTypes);
     571
     572    if (status != 0) {
     573        psFitsError(status, true, "Unable to create FITS table with %d columns and %d rows",
     574                    table->numCols, table->numRows);
     575        return false;
     576    }
     577
     578    // Write header
     579    if (header && !psFitsWriteHeader(fits, header)) {
     580        psError(PS_ERR_IO, false, "Unable to write FITS header.\n");
     581        return false;
     582    }
     583
     584    // write the header, if any.
     585    if (extname && strlen(extname) > 0) {
     586        if (!psFitsSetExtName(fits, extname)) {
     587            psError(PS_ERR_IO, false, "Unable to write FITS header extension name.\n");
     588            return false;
     589        }
     590    }
     591
     592    if (writeData) {
     593        // psMetadataIteratorSet(colSpecsIter, PS_LIST_HEAD);
     594        for (long colNum = 1; colNum <= table->numCols; colNum++) {
     595            // Note: colNum is unit-indexed, because it's for cfitsio
     596            psFitsTableColumn *column = &table->columns[colNum - 1];
     597            // colSpec *spec = colSpecItem->data.V; // The specification
     598            if (PS_DATA_IS_PRIMITIVE(column->type)) {
     599#ifdef notdef
     600                size_t dataSize = PSELEMTYPE_SIZEOF(column->type); // Size (in bytes) of this type
     601                psVector *columnData = psVectorAlloc(table->n, column->type); // The raw row data, to be written
     602                psVectorInit(columnData, 0);
     603                for (long i = 0; i < table->numRows; i++) {
     604                    psMetadata *row = table->data[i]; // The row of interest
     605                    psMetadataItem *dataItem = psMetadataLookup(row, colSpecItem->name); // Value of interest
     606                    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 holder
     610                        // XXX this should insert a NAN for float / double and an appropriate blank for int types
     611                        // XXX for the moment I am putting in 0.0
     612                        memset(&columnData->data.U8[i * dataSize], 0, dataSize);
     613                    }
     614                }
     615#endif
     616
     617                int fitsDataType;           // Data type for cfitsio
     618                p_psFitsTypeToCfitsio(column->type, NULL, NULL, &fitsDataType);
     619                fits_write_col(fits->fd,
     620                               fitsDataType,
     621                               colNum, // column number
     622                               1, // first row
     623                               1, // first element
     624                               table->numRows, // number of rows
     625                               column->data.U8, // the data
     626                               &status);
     627                // psFree(columnData);
     628            } else {
     629                switch (column->type) {
     630                  case PS_DATA_STRING: {
     631#ifdef notdef
     632                      psArray *strings = psArrayAlloc(table->n); // Array of strings
     633                      for (long i = 0; i < table->n; i++) {
     634                          psMetadata *row = table->data[i]; // The row of interest
     635                          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#endif
     640                      fits_write_col_str(fits->fd, colNum, 1, 1, table->numRows, (char**)column->data.str, &status);
     641                      // psFree(strings);
     642                      break;
     643                  }
     644                  case PS_DATA_VECTOR: {
     645                      size_t dataSize = PSELEMTYPE_SIZEOF(column->vectorType); // Size of data, in bytes
     646                      psVector *columnData = psVectorAlloc(column->elementSize * table->numRows * dataSize, PS_TYPE_U8);
     647                      psVectorInit(columnData, 0);
     648                      for (long i = 0; i < table->numRows; i++) {
     649#ifdef notdef
     650                          psMetadata *row = table->data[i]; // The row of interest
     651                          psMetadataItem* dataItem = psMetadataLookup(row, colSpecItem->name);
     652                          if (dataItem->type != PS_DATA_VECTOR) {
     653                              // Just in case --- get a zero instead of some weird result
     654                              continue;
     655                          }
     656                          psVector *vector = dataItem->data.V;
     657#endif
     658                          psVector *vector = column->data.vec[i];
     659                          memcpy(&columnData->data.U8[i * dataSize * column->elementSize], vector->data.U8,
     660                                 vector->n * dataSize);
     661                      }
     662
     663                      int fitsDataType;           // Data type for cfitsio
     664                      p_psFitsTypeToCfitsio(column->vectorType, NULL, NULL, &fitsDataType);
     665                      fits_write_col(fits->fd, fitsDataType, colNum, 1, 1, table->numRows * column->elementSize,
     666                                     columnData->data.U8, &status);
     667                      psFree(columnData);
     668                      break;
     669                  }
     670                  default:
     671                    psAbort("Should never get here.\n");
     672                }
     673            }
     674
     675            // Check error status from writing column
     676            if (status != 0) {
     677                psFitsError(status, true, "Unable to write column %ld of FITS table", colNum);
     678                return false;
     679            }
     680        }
     681    }
     682
     683    // This forces a re-scan of the header to ensure everything's kosher.  We found this occassionally
     684    // necessary for compressed images, which are tables, so perhaps it helps here too.  I guess it can't
     685    // hurt.
     686    ffrdef(fits->fd, &status);
     687    if (psFitsError(status, true, "Could not re-scan HDU.")) {
     688        return false;
     689    }
     690
     691    return true;
     692}
     693
     694// END OF new insert table
     695
     696bool psFitsWriteTableNew(psFits* fits,
     697                      const psMetadata* header,
     698                      psFitsTable* table,
     699                      const char *extname)
     700{
     701    PS_ASSERT_FITS_NON_NULL(fits, false);
     702    PS_ASSERT_FITS_WRITABLE(fits, false);
     703    if (!psFitsMoveLast(fits)) {
     704        psError(PS_ERR_UNKNOWN, false, "Unable to move to last extension to write table");
     705        return false;
     706    }
     707    bool writeData = table->numRows > 0;
     708    return fitsInsertTableNew(fits, header, table, extname, true, writeData);
     709}
     710
     711#ifdef notdef
    342712
    343713psArray* psFitsReadTableColumn(const psFits* fits,
  • trunk/psLib/src/fits/psFitsTableNew.h

    r32217 r32228  
    1414
    1515typedef struct {
    16     /* psString    name; */
     16    psString    name;
    1717    psDataType  type;
     18    psDataType  vectorType;             // type inside if Vector
     19    int         elementSize;            // 1 for primitives, strlen for strings
     20                                        // vector length for vectors
    1821    // only types supported by fits tables will be implemented
    1922    union {
     
    4952
    5053psFitsTable *psFitsReadTableNew(const psFits *fits);
    51 bool psFitsWriteTableNew(psFits *fits, psFitsTable *table, const char *extname);
     54bool psFitsWriteTableNew(psFits *fits, const psMetadata *header, psFitsTable *table, const char *extname);
    5255bool psFitsTableCensor(psFitsTable *table, bool *rowMask);
    5356
Note: See TracChangeset for help on using the changeset viewer.