IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Ignore:
Timestamp:
Oct 3, 2007, 11:27:21 AM (19 years ago)
Author:
Paul Price
Message:

Merging branch with FITS compression development.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/psLib/src/fits/psFits.c

    r14878 r15179  
    77 *  @author Robert DeSonia, MHPCC
    88 *
    9  *  @version $Revision: 1.71 $ $Name: not supported by cvs2svn $
    10  *  @date $Date: 2007-09-18 03:01:17 $
     9 *  @version $Revision: 1.72 $ $Name: not supported by cvs2svn $
     10 *  @date $Date: 2007-10-03 21:27:21 $
    1111 *
    1212 *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
     
    2020
    2121#include "psFits.h"
     22#include "psFitsHeader.h"
    2223#include "string.h"
    2324#include "psError.h"
     
    6566            return false;
    6667        }
    67         fits->fd = NULL;
     68        fits->fd = NULL;
    6869    }
    6970    return true;
     
    7475    if (!fits) return;
    7576    if (fits->fd) {
    76         fitsClose(fits);
     77        fitsClose(fits);
    7778    }
    7879    psFree (fits->extword);
     
    8182bool psFitsClose(psFits* fits)
    8283{
    83     if (fits == NULL) {
    84         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    85                 _("The input psFits object can not NULL."));
    86         return false;
    87     }
     84    PS_ASSERT_FITS_NON_NULL(fits, false);
    8885
    8986    bool status = fitsClose(fits);
     
    9592psFits* psFitsOpen(const char* name, const char* mode)
    9693{
     94    PS_ASSERT_STRING_NON_EMPTY(name, NULL);
     95
    9796    int status = 0;
    9897    fitsfile *fptr = NULL;      /* Pointer to the FITS file */
    99 
    100     if (name == NULL) {
    101         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    102                 _("Specified filename can not be NULL."));
    103         return NULL;
    104     }
    10598
    10699    /* check the mode to determine how to open/create file */
     
    131124        if (access(name, F_OK) == 0) {
    132125            // file exists, delete old one first
    133             remove
    134                 (name);
     126            remove(name);
    135127        }
    136128
     
    140132        (void)fits_create_file
    141133        #endif
    142         (&fptr,
    143          name,
    144          &status);
     134        (&fptr, name, &status);
    145135        if (fptr == NULL || status != 0) {
    146             char fitsErr[MAX_STRING_LENGTH]
    147             ;
     136            char fitsErr[MAX_STRING_LENGTH];
    148137            fits_get_errstatus(status, fitsErr);
    149138            psError(PS_ERR_IO, true,
     
    158147        (void)fits_open_file
    159148        #endif
    160         (&fptr,
    161          name,
    162          iomode,
    163          &status);
     149        (&fptr, name, iomode, &status);
    164150        if (fptr == NULL || status != 0) {
    165             char fitsErr[MAX_STRING_LENGTH]
    166             ;
     151            char fitsErr[MAX_STRING_LENGTH];
    167152            fits_get_errstatus(status, fitsErr);
    168153            psError(PS_ERR_IO, true,
     
    177162    fits->writable = (iomode == READWRITE);
    178163    fits->extword = NULL;
     164    fits->conventions.compression = true;
    179165    psMemSetDeallocator(fits,(psFreeFunc)fitsFree);
    180166
     
    182168}
    183169
    184 static void psFitsOptionsFree(psFitsOptions *opt)
    185 {
    186     psFree(opt->tilesize);
    187 }
    188 
    189 psFitsOptions* psFitsOptionsAlloc(
     170psErrorCode p_psFitsError(const char* filename, unsigned int lineno, const char* func, int status,
     171                          bool new, const char *errorMsg, ...)
     172{
     173    if (status == 0) {
     174        return PS_ERR_NONE;
     175    }
     176
     177    va_list ap;                         // Variable arguments
     178    va_start(ap, errorMsg);
     179    psString msg = NULL;                // Message to pass to psError
     180    psStringAppendV(&msg, errorMsg, ap);
     181    va_end(ap);
     182
     183    char cfitsioMsg[MAX_STRING_LENGTH];   // Error message from cfitsio
     184    (void)fits_get_errstatus(status, cfitsioMsg);
     185
     186    psStringAppend(&msg, "[CFITSIO error: %s]", cfitsioMsg);
     187
     188    psErrorCode code = p_psError(filename, lineno, func, PS_ERR_IO, new, msg); // Error code
     189    psFree(msg);
     190    return code;
     191}
     192
     193static void psFitsCompressionFree(psFitsCompression *comp)
     194{
     195    PS_ASSERT_PTR_NON_NULL(comp,);
     196    psFree(comp->tilesize);
     197}
     198
     199psFitsCompression* psFitsCompressionAlloc(
    190200    psFitsCompressionType type,         ///< type of compression
    191201    psVector *tilesize,                 ///< vector defining compression tile size
     
    195205)
    196206{
    197     psFitsOptions *opt = psAlloc(sizeof(psFitsOptions));
    198 
    199     opt->type = type;
    200     opt->tilesize = psVectorCopy(NULL, tilesize, PS_DATA_S64);
    201     opt->noisebits = noisebits;
    202     opt->scale = scale;
    203     opt->smooth = smooth;
    204 
    205     psMemSetDeallocator(opt, (psFreeFunc) psFitsOptionsFree);
    206 
    207     return opt;
     207    psFitsCompression *comp = psAlloc(sizeof(psFitsCompression));
     208    psMemSetDeallocator(comp, (psFreeFunc) psFitsCompressionFree);
     209
     210    comp->type = type;
     211    comp->tilesize = psVectorCopy(NULL, tilesize, PS_DATA_S64);
     212    comp->noisebits = noisebits;
     213    comp->scale = scale;
     214    comp->smooth = smooth;
     215
     216    return comp;
    208217}
    209218
     
    224233}
    225234
    226 // move to the first HDU where extword == extname.  this is equivalent to fits_movnam_hdu() for
    227 // a user-defined word in place of EXTNAME
    228 bool p_psFitsMoveExtName_UserKey(const psFits *fits,
    229                                  const char *extname,
    230                                  const char *extword)
    231 {
    232     PS_ASSERT_PTR_NON_NULL(fits,    false);
    233     PS_ASSERT_PTR_NON_NULL(extname, false);
    234     PS_ASSERT_PTR_NON_NULL(extword, false);
    235 
    236     int hdutype = 0;
    237     char name[MAX_STRING_LENGTH];
    238     char extstring[MAX_STRING_LENGTH];
    239 
    240     sprintf (extstring, "'%s'", extname);
    241 
    242     // NOTE: fits_* return 0 for success
    243     for (int i = 1; true; i++) {
    244         // are we able to read the next HDU?
    245 
    246         int status = 0;
    247         if (fits_movabs_hdu(fits->fd, i, &hdutype, &status)) {
    248             char fitsErr[MAX_STRING_LENGTH];
    249             fits_get_errstatus(status, fitsErr);
    250             psError(PS_ERR_LOCATION_INVALID, true,
    251                     _("Could not find HDU with %s = '%s'. CFITSIO Error: %s"),
    252                     extword, extname, fitsErr);
    253             return false;
    254         }
    255         // is there a keyword called 'extword'? (read as string regardless of type)
    256         status = 0;
    257         if (fits_read_keyword(fits->fd, (char *)extword, name, NULL, &status)) {
    258             continue;
    259         }
    260         // if this was read as a string, we will have leading and trailing single-quotes
    261         // try both for comparison
    262        
    263         // do we have the right hdu (names match)?
    264         if (!strcmp (name, extname) || !strcmp (name, extstring)) {
    265             return true;
    266         }
    267     }
    268     psAbort("we should not reach here");
    269 }
    270 
    271 // XXX I will need to define a low-level function p_psFitsMoveExtName_UserKey () which
    272 // uses fits_movabs_hdu() to replicate the functionality of fits_movnam_hdu using an
    273 // alternate name for EXTNAME
     235// Files compressed with cfitsio's "imcopy" program may have multiple EXTNAME keywords, with the first set to
     236// COMPRESSED_IMAGE.  However, fits_movnam_hdu won't find the second (proper) value of EXTNAME, and so can
     237// fail to find a perfectly legitimate extension, simply because imcopy does something silly.  However, we
     238// really want to be able to read these files (MegaCam data are shipped as imcopy-compressed images).
     239// Therefore, we implement our own version of moving to an extension specified by name.  The pure cfitsio
     240// version is used if "conventions.compression" handling is turned off in the psFits structure.
    274241bool psFitsMoveExtName(const psFits* fits,
    275242                       const char* extname)
    276243{
    277     int status = 0;
    278 
    279     if (fits == NULL) {
    280         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    281                 _("The input psFits object can not NULL."));
    282         return false;
    283     }
    284 
    285     if (extname == NULL) {
    286         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    287                 _("Specified extension name can not be NULL."));
    288         return false;
    289     }
    290 
    291     if (fits->extword != NULL) {
    292         bool result = p_psFitsMoveExtName_UserKey(fits, extname, fits->extword);
    293         return (result);
    294     }
    295 
    296     if (fits_movnam_hdu(fits->fd, ANY_HDU, (char*)extname, 0, &status) != 0) {
    297         char fitsErr[MAX_STRING_LENGTH];
    298         fits_get_errstatus(status, fitsErr);
    299         psError(PS_ERR_LOCATION_INVALID, true,
    300                 _("Could not find HDU '%s'. CFITSIO Error: %s"),
    301                 extname, fitsErr);
    302         return false;
    303     }
    304 
    305     return true;
     244    PS_ASSERT_FITS_NON_NULL(fits, false);
     245    PS_ASSERT_STRING_NON_EMPTY(extname, false);
     246
     247    int status = 0;
     248
     249    if (!fits->conventions.compression && !fits->extword) {
     250        // User wants to use cfitsio.  Good luck to them!
     251        if (fits_movnam_hdu(fits->fd, ANY_HDU, (char*)extname, 0, &status) != 0) {
     252            psFitsError(status, true, _("Could not find HDU '%s'"), extname);
     253            return false;
     254        }
     255        return true;
     256    }
     257
     258    bool ignoreCI = (fits->conventions.compression &&
     259                     (strcmp(extname, "COMPRESSED_IMAGE") != 0)); // Ignore COMPRESSED_IMAGE extension name?
     260    char *extword = (fits->extword ? fits->extword : "EXTNAME"); // Word to use as extension name
     261
     262#if 0
     263    // XXX Future optimisation: loop through from the current HDU to the end, then from the start to the
     264    // current position.  This will save seeking through the file multiple times.
     265    int currentExt = psFitsGetExtNum(fits); // Current extension number
     266    int numExt = psFitsGetSize(fits);   // Total number of extensions
     267#endif
     268
     269    for (int i = 1; true; i++) {
     270        int hdutype = 0;
     271        if (fits_movabs_hdu(fits->fd, i, &hdutype, &status)) {
     272            // We've run off the end
     273            psFitsError(status, true, _("Could not find HDU with %s = '%s'"), extword, extname);
     274            return false;
     275        }
     276        // Is there a keyword called 'extword'? (read as string regardless of type)
     277        char name[MAX_STRING_LENGTH];  // Name of extension
     278        if (fits_read_keyword(fits->fd, extword, name, NULL, &status)) {
     279            // It doesn't exist in the header.
     280            // This isn't the extension you're looking for.  Move along.
     281            status = 0;
     282            continue;
     283        }
     284        char *fixed = p_psFitsHeaderParseString(name); // Parsed version (removing quotes and spaces)
     285
     286        if (ignoreCI && strcmp(fixed, "COMPRESSED_IMAGE") == 0) {
     287            // Read it again, Sam
     288            if (fits_read_keyword(fits->fd, extword, name, NULL, &status)) {
     289                status = 0;
     290                continue;
     291            }
     292            fixed = p_psFitsHeaderParseString(name);
     293        }
     294
     295        if (strcmp(fixed, extname) == 0) {
     296            // We've arrived
     297            return true;
     298        }
     299    }
     300    psAbort("Should never reach here.");
    306301}
    307302
     
    310305                      bool relative)
    311306{
    312     if (fits == NULL) {
    313         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    314                 _("The input psFits object can not NULL."));
    315         return false;
    316     }
     307    PS_ASSERT_FITS_NON_NULL(fits, false);
    317308
    318309    int status = 0;
     
    346337bool psFitsMoveLast(psFits* fits)
    347338{
    348     if (fits == NULL) {
    349         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    350                 _("The input psFits object can not NULL."));
    351         return false;
    352     }
     339    PS_ASSERT_FITS_NON_NULL(fits, false);
     340
    353341    int size = psFitsGetSize(fits);
    354342    if (size == 0) { // empty file -- no action needed
     
    361349int psFitsGetExtNum(const psFits* fits)
    362350{
     351    PS_ASSERT_FITS_NON_NULL(fits, false);
    363352    int hdunum;
    364 
    365     if (fits == NULL) {
    366         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    367                 _("The input psFits object can not NULL."));
    368         return PS_FITS_TYPE_NONE;
    369     }
    370 
    371 
    372353    return fits_get_hdu_num(fits->fd,&hdunum) - 1;
    373354}
     
    375356psString psFitsGetExtName(const psFits* fits)
    376357{
    377     if (fits == NULL) {
    378         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    379                 _("The input psFits object can not NULL."));
    380         return NULL;
    381     }
     358    PS_ASSERT_FITS_NON_NULL(fits, NULL);
    382359
    383360    int status = 0;
     
    389366        psError(PS_ERR_BAD_PARAMETER_NULL, true,
    390367                _("Header keyword %s is not found"), extword);
    391         return NULL;
     368        return NULL;
    392369    }
    393370    return psStringCopy(name);
     
    396373bool psFitsSetExtName(psFits* fits, const char* name)
    397374{
    398     if (fits == NULL) {
    399         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    400                 _("The input psFits object can not NULL."));
    401         return false;
    402     }
    403 
    404     if (name == NULL) {
    405         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    406                 _("Specified extension name can not be NULL."));
    407         return false;
    408     }
     375    PS_ASSERT_FITS_NON_NULL(fits, false);
     376    PS_ASSERT_STRING_NON_EMPTY(name, false);
    409377
    410378    int status = 0;
     
    428396                        bool relative)
    429397{
    430     if (fits == NULL) {
    431         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    432                 _("The input psFits object can not NULL."));
    433         return false;
    434     }
     398    PS_ASSERT_FITS_NON_NULL(fits, false);
    435399
    436400    if (! fits->writable) {
     
    466430                         const char* extname)
    467431{
    468     if (fits == NULL) {
    469         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    470                 _("The input psFits object can not NULL."));
    471         return false;
    472     }
     432    PS_ASSERT_FITS_NON_NULL(fits, false);
     433    PS_ASSERT_STRING_NON_EMPTY(extname, false);
    473434
    474435    if (! fits->writable) {
     
    504465int psFitsGetSize(const psFits* fits)
    505466{
    506     if (fits == NULL) {
    507         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    508                 _("The input psFits object can not NULL."));
    509         return 0;
    510     }
     467    PS_ASSERT_FITS_NON_NULL(fits, 0);
    511468
    512469    int num = 0;
     
    527484psFitsType psFitsGetExtType(const psFits* fits)
    528485{
    529     if (fits == NULL) {
    530         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    531                 _("The input psFits object can not NULL."));
    532         return PS_FITS_TYPE_NONE;
    533     }
     486    PS_ASSERT_FITS_NON_NULL(fits, PS_FITS_TYPE_NONE);
    534487
    535488    int status = 0;
     
    556509bool psFitsTruncate(psFits* fits)
    557510{
    558     if (fits == NULL) {
    559         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    560                 _("The input psFits object can not NULL."));
    561         return PS_FITS_TYPE_NONE;
    562     }
     511    PS_ASSERT_FITS_NON_NULL(fits, NULL);
    563512
    564513    if (! fits->writable) {
     
    597546)
    598547{
     548    PS_ASSERT_FITS_NON_NULL(fits, false);
     549
    599550    // convert psFitsCompressionType to cfitsio compression types
    600551    int comptype;
     
    640591        psAbort("can't map (long) type to a psLib type");
    641592    }
     593    psFree(dim);
    642594    // status check belongs to fits_set_tile_dim() call
    643595    if (status) {
     
    681633}
    682634
    683 
    684 bool psFitsSetOptions(
     635psFitsCompression *psFitsCompressionGet(psFits* fits)
     636{
     637    PS_ASSERT_FITS_NON_NULL(fits, NULL);
     638
     639    int status = 0;                     // cfitsio status
     640
     641    psFitsCompressionType type = psFitsCompressionGetType(fits);
     642    if (type < 0) {
     643        psError(PS_ERR_UNKNOWN, false, "Unable to get compression type.");
     644        return NULL;
     645    }
     646
     647    psElemType tileType;                // Type corresponding to "long"
     648    if (sizeof(long) == sizeof(psS64)) {
     649        tileType = PS_TYPE_S64;
     650    } else if (sizeof(long) == sizeof(psS32)) {
     651        tileType = PS_TYPE_S32;
     652    } else {
     653        psAbort("can't map (long) type to a psLib type");
     654    }
     655
     656    psVector *tiles = psVectorAlloc(3, tileType); // Tile sizes
     657    if (fits_get_tile_dim(fits->fd, 3, (long*)tiles->data.U8, &status)) {
     658        psFitsError(status, true, "Unable to get compression tile sizes.");
     659        psFree(tiles);
     660        return NULL;
     661    }
     662
     663    int noisebits;                      // Noise bits for compression
     664    if (fits_get_noise_bits(fits->fd, &noisebits, &status)) {
     665        psFitsError(status, true, "Unable to get compression noise bits.");
     666        psFree(tiles);
     667        return NULL;
     668    }
     669
     670    int hscale = 0, hsmooth = 0;        // Scaling and smoothing for HCOMPRESS
     671
     672#if FITS_HCOMP
     673    if (fits_get_hcomp_scale(fits->fd, &hscale, &status)) {
     674        psFitsError(status, true, "Unable to get HCOMPRESS scaling.");
     675        psFree(tiles);
     676        return NULL;
     677    }
     678    if (fits_get_hcomp_smooth(fits->fd, &hsmooth, &status)) {
     679        psFitsError(status, true, "Unable to get HCOMPRESS smoothing.");
     680        psFree(tiles);
     681        return NULL;
     682    }
     683#endif // FITS_HCOMP
     684
     685    psFitsCompression *compress = psFitsCompressionAlloc(type, tiles, noisebits, hscale, hsmooth);
     686    psFree(tiles);                      // Drop reference
     687
     688    return compress;
     689}
     690
     691psFitsCompressionType psFitsCompressionGetType(psFits* fits)
     692{
     693    PS_ASSERT_FITS_NON_NULL(fits, -1);
     694
     695    int status = 0;                     // cfitsio status
     696    int comptype = 0;                   // cfitsio compression type
     697    if (fits_get_compression_type(fits->fd, &comptype, &status)) {
     698        psFitsError(status, true, "Unable to get compression type.");
     699        return -1;
     700    }
     701
     702    psFitsCompressionType type;
     703    switch (comptype) {
     704      case 0:
     705        type = PS_FITS_COMPRESS_NONE;
     706        break;
     707      case GZIP_1:
     708        type = PS_FITS_COMPRESS_GZIP;
     709        break;
     710      case RICE_1:
     711        type = PS_FITS_COMPRESS_RICE;
     712        break;
     713      case HCOMPRESS_1:
     714        type = PS_FITS_COMPRESS_HCOMPRESS;
     715        break;
     716      case PLIO_1:
     717        type = PS_FITS_COMPRESS_PLIO;
     718        break;
     719      default:
     720        psError(PS_ERR_UNKNOWN, true, "cfitsio reports unknown compression type.");
     721        return -1;
     722    }
     723
     724    return type;
     725}
     726
     727
     728bool psFitsCompressionApply(
    685729    psFits* fits,                       ///< psFits object to close
    686     psFitsOptions *opt                  ///< options object
     730    psFitsCompression *comp             ///< options object
    687731)
    688732{
    689     return psFitsSetCompression(
    690             fits,
    691             opt->type,
    692             opt->tilesize,
    693             opt->noisebits,
    694             opt->scale,
    695             opt->smooth);
     733    return psFitsSetCompression(fits, comp->type, comp->tilesize, comp->noisebits, comp->scale, comp->smooth);
    696734}
    697735
     
    826864
    827865
     866psFitsCompressionType psFitsCompressionTypeFromString(const char *string)
     867{
     868    if (!string || strlen(string) == 0) {
     869        psWarning("Unable to identify compression type --- none set.");
     870        return PS_FITS_COMPRESS_NONE;
     871    }
     872
     873    if (strcmp(string, "GZIP") == 0) return PS_FITS_COMPRESS_GZIP;
     874    if (strcmp(string, "RICE") == 0) return PS_FITS_COMPRESS_RICE;
     875    if (strcmp(string, "HCOMPRESS") == 0) return PS_FITS_COMPRESS_HCOMPRESS;
     876    if (strcmp(string, "PLIO") == 0) return PS_FITS_COMPRESS_PLIO;
     877
     878    psWarning("Unable to identify compression type (%s) --- none set.", string);
     879    return PS_FITS_COMPRESS_NONE;
     880}
Note: See TracChangeset for help on using the changeset viewer.