Exemple #1
0
int sdfits_create(struct sdfits *sf) {
    int itmp, *status;
    char ctmp[40];
    struct hdrinfo *hdr;

    hdr = &(sf->hdr);        // dereference the ptr to the header struct
    status = &(sf->status);  // dereference the ptr to the CFITSIO status

    // Initialize the key variables if needed
    if (sf->new_file == 1) {  // first time writing to the file
        sf->status = 0;
        sf->tot_rows = 0;
        sf->N = 0L;
        sf->T = 0.0;
        sf->mode = 'w';

        // Create the output directory if needed
        char datadir[1024];
        strncpy(datadir, sf->basefilename, 1023);
        char *last_slash = strrchr(datadir, '/');
        if (last_slash!=NULL && last_slash!=datadir) {
            *last_slash = '\0';
            printf("Using directory '%s' for output.\n", datadir);
            char cmd[1024];
            sprintf(cmd, "mkdir -m 1777 -p %s", datadir);
            system(cmd);
        }
        sf->new_file = 0;
    }
    sf->filenum++;
    sf->rownum = 1;

    sprintf(sf->filename, "%s_%04d.fits", sf->basefilename, sf->filenum);

    // Create basic FITS file from our template
    char *vegas_dir = getenv("VEGAS_DIR");
    char template_file[1024];
    if (vegas_dir==NULL) {
        fprintf(stderr, 
                "Error: VEGAS_DIR environment variable not set, exiting.\n");
        exit(1);
    }
    printf("Opening file '%s'\n", sf->filename);
    sprintf(template_file, "%s/%s", vegas_dir, SDFITS_TEMPLATE);
    fits_create_template(&(sf->fptr), sf->filename, template_file, status);

    // Check to see if file was successfully created
    if (*status) {
        fprintf(stderr, "Error creating sdfits file from template.\n");
        fits_report_error(stderr, *status);
        exit(1);
    }

    // Go to the primary HDU
    fits_movabs_hdu(sf->fptr, 1, NULL, status);

    // Update the keywords that need it
    fits_get_system_time(ctmp, &itmp, status);      // date the file was written
    fits_update_key(sf->fptr, TSTRING, "DATE", ctmp, NULL, status);

    // Go to the SINGLE DISH HDU
    fits_movnam_hdu(sf->fptr, BINARY_TBL, "SINGLE DISH", 0, status);

    // Update the keywords that need it
    fits_update_key(sf->fptr, TSTRING, "TELESCOP", hdr->telescope,NULL, status);
    fits_update_key(sf->fptr, TDOUBLE, "BANDWID", &(hdr->bandwidth), NULL, status);
    fits_update_key(sf->fptr, TSTRING, "DATE-OBS", hdr->date_obs, NULL, status);
    fits_update_key(sf->fptr, TDOUBLE, "TSYS", &(hdr->tsys), NULL, status);

    fits_update_key(sf->fptr, TSTRING, "PROJID", hdr->projid, NULL, status);
    fits_update_key(sf->fptr, TSTRING, "FRONTEND", hdr->frontend, NULL, status);
    fits_update_key(sf->fptr, TDOUBLE, "OBSFREQ", &(hdr->obsfreq), NULL, status);
    fits_update_key(sf->fptr, TDOUBLE, "SCAN", &(hdr->scan), NULL, status);

    fits_update_key(sf->fptr, TSTRING, "INSTRUME", hdr->instrument, NULL, status);
    fits_update_key(sf->fptr, TSTRING, "CAL_MODE", hdr->cal_mode, NULL, status);
    if (strcmp("OFF", hdr->cal_mode) != 0)
    {
        fits_update_key(sf->fptr, TDOUBLE, "CAL_FREQ", &(hdr->cal_freq), NULL, status);
        fits_update_key(sf->fptr, TDOUBLE, "CAL_DCYC", &(hdr->cal_dcyc), NULL, status);
        fits_update_key(sf->fptr, TDOUBLE, "CAL_PHS", &(hdr->cal_phs), NULL, status);
    }
    fits_update_key(sf->fptr, TINT,    "NPOL", &(hdr->npol), NULL, status);
    fits_update_key(sf->fptr, TINT,    "NCHAN", &(hdr->nchan), NULL, status);
    fits_update_key(sf->fptr, TDOUBLE, "CHAN_BW", &(hdr->chan_bw), NULL, status);
    fits_update_key(sf->fptr, TINT,    "NSUBBAND", &(hdr->nsubband), NULL, status);
    fits_update_key(sf->fptr, TDOUBLE, "EFSAMPFR", &(hdr->efsampfr), NULL, status);
    fits_update_key(sf->fptr, TDOUBLE, "FPGACLK", &(hdr->fpgaclk), NULL, status);
    fits_update_key(sf->fptr, TDOUBLE, "HWEXPOSR", &(hdr->hwexposr), NULL, status);
    fits_update_key(sf->fptr, TDOUBLE, "FILTNEP", &(hdr->filtnep), NULL, status);
    fits_update_key(sf->fptr, TDOUBLE, "STTMJD", &(hdr->sttmjd), NULL, status);

    // Update the column sizes for the colums containing arrays
    itmp = hdr->nsubband * hdr->nchan * 4;                          //num elements, not bytes
    fits_modify_vector_len(sf->fptr, 20, itmp, status);             // DATA
    fits_modify_vector_len(sf->fptr, 14, hdr->nsubband, status);    // SUBFREQ

    // Update the TDIM field for the data column
    sprintf(ctmp, "(%d,%d,4,1,1)", hdr->nchan, hdr->nsubband);
    fits_update_key(sf->fptr, TSTRING, "TDIM20", ctmp, NULL, status);

    fits_flush_file(sf->fptr, status);
   
    return *status;
}
Exemple #2
0
int main(int argc, char **argv)
{

    int i, iarg, nPix, anynul, status, mask;
    char help[4096];

    fitsfile *iPtr;
    int iBitpix, iNaxis;
    long iNaxes[MAXDIM];
    float *iRData=NULL;

    fitsfile *mPtr;
    int mBitpix, mNaxis;
    long mNaxes[MAXDIM];
    int *mRData=NULL;

    char  *inim=NULL, *maskim=NULL, *outim=NULL;
    float fillVal=D_FILLVAL;

    /* START */
    status  = 0;
    mask    = D_MASK;
    fillVal = D_FILLVAL;

    sprintf(help, "Usage : maskim [options]\n");
    sprintf(help, "%sRequired options:\n", help);
    sprintf(help, "%s   [-inim fitsfile]  : input image\n", help);
    sprintf(help, "%s   [-maskim fitsfile]: corresponding mask image\n", help);
    sprintf(help, "%s   [-outim fitsfile] : output masked image\n\n", help);
    sprintf(help, "%sOptions:\n", help);
    sprintf(help, "%s   [-fi fillval]    : Value of filled pixels (%.3f)\n", help, fillVal);
    sprintf(help, "%s   [-mask hex]      : Mask for bad pixels (0x%x)\n", help, mask);

    /* read in command options. j counts # of required args given */
    for (iarg=1; iarg < argc; iarg++) {
        if (argv[iarg][0]=='-') {
            if (strcasecmp(argv[iarg]+1,"inim")==0) {
                inim = argv[++iarg];
            } else if (strcasecmp(argv[iarg]+1,"maskim")==0) {
                maskim = argv[++iarg];
            } else if (strcasecmp(argv[iarg]+1,"outim")==0) {
                outim = argv[++iarg];
            } else if (strcasecmp(argv[iarg]+1,"fi")==0) {
                sscanf(argv[++iarg], "%f", &fillVal);
            } else if (strcasecmp(argv[iarg]+1,"mask")==0) {
                sscanf(argv[++iarg], "%d", &mask);
            } else {
                fprintf(stderr, "Unknown option : %s\n", argv[iarg]);
                exit(1);
            }
        } else {
            fprintf(stderr, "Unexpected string encountered on command line : %s\n", argv[iarg]);
            exit(1);
        }
    }
    /* read in command options */
    if (argc < 2) {
        fprintf(stderr, "%s\n", help);
        exit(1);
    }

    /* insanity checking */
    if ( !(inim) ) {
        fprintf(stderr, "FATAL ERROR inim is required command line option\n");
        exit(1);
    }
    if ( !(maskim) ) {
        fprintf(stderr, "FATAL ERROR maskim is required command line option\n");
        exit(1);
    }
    if ( !(outim) ) {
        fprintf(stderr, "FATAL ERROR outim is required command line option\n");
        exit(1);
    }

    /* open up, get bitpix, # dimensions, image size */
    if ( fits_open_file(&iPtr, inim, 0, &status) ||
            fits_get_img_param(iPtr, 2, &iBitpix, &iNaxis, iNaxes, &status) ) {
        printError(status);
    }
    if ( fits_open_file(&mPtr, maskim, 0, &status) ||
            fits_get_img_param(mPtr, 2, &mBitpix, &mNaxis, mNaxes, &status) ) {
        printError(status);
    }

    assert(iNaxes[0] == mNaxes[0]);
    assert(iNaxes[1] == mNaxes[1]);

    nPix = iNaxes[0]*iNaxes[1];

    iRData = (float *)realloc(iRData, nPix*sizeof(float));
    mRData = (int *)realloc(mRData, nPix*sizeof(int));
    if (iRData == NULL || mRData == NULL) {
        fprintf(stderr, "Cannot Allocate Standard Data Arrays\n");
        exit (1);
    }
    memset(iRData,   0.0, nPix*sizeof(float));
    memset(mRData,   0x0, nPix*sizeof(int));

    if (fits_read_img(iPtr, TFLOAT, 1, nPix, 0, iRData, &anynul, &status) ||
            fits_read_img(mPtr, TINT,   1, nPix, 0, mRData, &anynul, &status) ||
            fits_close_file(mPtr, &status))
        printError(status);

    /* do the masking */
    for (i = nPix; i--; )
        if (mRData[i] & mask)
            iRData[i] = fillVal;

    /* reuse mptr and help */
    sprintf(help, "!%s", outim);
    if (fits_create_template(&mPtr, help, inim, &status) ||
            fits_write_img(mPtr, TFLOAT, 1, nPix, iRData, &status) ||
            fits_close_file(mPtr, &status) ||
            fits_close_file(iPtr, &status))
        printError(status);

    free(iRData);
    free(mRData);

    return 0;
}
//----------------------------------------------------------
int etfits_create(etfits_t * etf) {
//----------------------------------------------------------
    int * status_p = &(etf->status);
    *status_p = 0;

    struct tm tm_now;
    time_t time_now;

    char file_name_str[256];

    // TODO enclose all init code in a do-as-needed block
    // Initialize the key variables if needed
    if (etf->new_run == 1) {  // first time writing this run
        etf->new_run = 0;
        etf->status = 0;
        etf->N = 0L;
        etf->T = 0.0;
        etf->mode = 'w';

        // Create the output directory if needed
        char datadir[1024];
        strncpy(datadir, etf->basefilename, 1023);
        char *last_slash = strrchr(datadir, '/');
        if (last_slash!=NULL && last_slash!=datadir) {
            *last_slash = '\0';
            printf("Using directory '%s' for output.\n", datadir);
            char cmd[1024];
            sprintf(cmd, "mkdir -m 1777 -p %s", datadir);
            system(cmd);
        }
    }   // end first time writing this run

    etf->tot_rows = 0;      // count rows per file

    // Form file name 
    time(&time_now);
    localtime_r(&time_now, &tm_now);
    sprintf(file_name_str, "%s_%04d_%04d%02d%02d_%02d%02d%02d", 
            etf->primary_hdr.receiver,
            etf->file_chan,
            1900+tm_now.tm_year, 1+tm_now.tm_mon, tm_now.tm_mday, 
            tm_now.tm_hour, tm_now.tm_min, tm_now.tm_sec); 
    sprintf(etf->filename_working, "%s_%s_%s.working", etf->basefilename, etf->hostname, file_name_str);  
    sprintf(etf->filename_fits,    "%s_%s_%s.fits",    etf->basefilename, etf->hostname, file_name_str);  

    // Create basic FITS file from our template
    char template_file[1024];
    //printf("Opening file '%s'\n", etf->filename);
    sprintf(template_file, "%s/%s", etf->s6_dir, ETFITS_TEMPLATE);
    if(! *status_p) fits_create_template(&(etf->fptr), etf->filename_working, template_file, status_p);

    // Check to see if file was successfully created
    if (*status_p) {
        hashpipe_error(__FUNCTION__, "Error creating sdfits file from template");
        //fprintf(stderr, "Error creating sdfits file from template.\n");
        fits_report_error(stderr, *status_p);
    } else {
        etf->file_open = 1;     // successful file open
    }

    return *status_p;
}
int psrfits_create(struct psrfits *pf) {
    int itmp, *status;
    long long lltmp;
    long double ldtmp;
    double dtmp;
    char ctmp[40];
    struct hdrinfo *hdr;
    struct foldinfo *fld;

    hdr = &(pf->hdr);        // dereference the ptr to the header struct
    status = &(pf->status);  // dereference the ptr to the CFITSIO status
    fld = &(pf->fold);       // ptr to foldinfo struct

    // Figure out what mode this is 
    int mode=0;
    mode = psrfits_obs_mode(hdr->obs_mode);
    if (mode==fold) {
        if (hdr->onlyI)
            printf("Warning!  In folding mode and ONLY_I is set!\n");
        if (hdr->ds_time_fact > 1)
            printf("Warning!  In folding mode and DS_TIME is > 1!\n");
        if (hdr->ds_freq_fact > 1)
            printf("Warning!  In folding mode and DS_FREQ is > 1!\n");
    }

    // Initialize the key variables if needed
    if (pf->filenum == 0) {  // first time writing to the file
        pf->status = 0;
        pf->tot_rows = 0;
        pf->N = 0L;
        pf->T = 0.0;
        hdr->offset_subint = 0;
        pf->mode = 'w';

        // Create the output directory if needed
        char datadir[1024];
        strncpy(datadir, pf->basefilename, 1023);
        char *last_slash = strrchr(datadir, '/');
        if (last_slash!=NULL && last_slash!=datadir) {
            *last_slash = '\0';
            printf("Using directory '%s' for output.\n", datadir);
            char cmd[1024];
            sprintf(cmd, "mkdir -m 1777 -p %s", datadir);
            system(cmd);
        }
    }
    pf->filenum++;
    pf->rownum = 1;
    hdr->offset_subint = pf->tot_rows;

    // Update the filename - don't include filenum for fold mode
    // TODO : use rf/cf extensions for psr/cals?
    if (mode==fold && pf->multifile!=1)
        sprintf(pf->filename, "%s.fits", pf->basefilename);
    else
        sprintf(pf->filename, "%s_%04d.fits", pf->basefilename, pf->filenum);

    // Create basic FITS file from our template
    // Fold mode template has additional tables (polyco, ephem)
    char template_dir[1024];
    char template_file[1024];
#ifdef PSRFITS_TEMPLATE_DIR
    sprintf(template_dir, "%s", PSRFITS_TEMPLATE_DIR);
#else
    char *guppi_dir = getenv("GUPPI_DIR");
    if (guppi_dir==NULL) {
        fprintf(stderr, 
                "Error: GUPPI_DIR environment variable not set, exiting.\n");
        exit(1);
    }
    sprintf(template_dir, "%s/src", guppi_dir);
#endif
    printf("Opening file '%s' ", pf->filename);
    if (mode==search) { 
        printf("in search mode.\n");
        sprintf(template_file, "%s/%s", template_dir, PSRFITS_SEARCH_TEMPLATE);
    } else if (mode==fold) { 
        printf("in fold mode.\n");
        sprintf(template_file, "%s/%s", template_dir, PSRFITS_FOLD_TEMPLATE);
    }
    fits_create_template(&(pf->fptr), pf->filename, template_file, status);

    // Check to see if file was successfully created
    if (*status) {
        fprintf(stderr, "Error creating psrfits file from template.\n");
        fits_report_error(stderr, *status);
        exit(1);
    }

    // Go to the primary HDU
    fits_movabs_hdu(pf->fptr, 1, NULL, status);

    // Update the keywords that need it
    fits_get_system_time(ctmp, &itmp, status);
    // Note:  this is the date the file was _written_, not the obs start date
    fits_update_key(pf->fptr, TSTRING, "DATE", ctmp, NULL, status);
    fits_update_key(pf->fptr, TSTRING, "TELESCOP", hdr->telescope,NULL, status);
    fits_update_key(pf->fptr, TSTRING, "OBSERVER", hdr->observer, NULL, status);
    fits_update_key(pf->fptr, TSTRING, "PROJID", hdr->project_id, NULL, status);
    fits_update_key(pf->fptr, TSTRING, "FRONTEND", hdr->frontend, NULL, status);
    fits_update_key(pf->fptr, TSTRING, "BACKEND", hdr->backend, NULL, status);
    if (hdr->onlyI || hdr->summed_polns) {
        if (!hdr->onlyI && hdr->npol > 1) {
            printf("Warning!:  Can't have %d polarizations _and_ be summed!\n", 
                   hdr->npol);
        }
        itmp = 2;
        fits_update_key(pf->fptr, TINT, "NRCVR", &itmp, NULL, status);
    } else {
        if (hdr->npol > 2) { // Can't have more than 2 real polns (i.e. NRCVR)
            itmp = 2;
            fits_update_key(pf->fptr, TINT, "NRCVR", &itmp, NULL, status);
        } else {
            fits_update_key(pf->fptr, TINT, "NRCVR", &(hdr->npol), NULL, status);
        }
    }
    fits_update_key(pf->fptr, TSTRING, "FD_POLN", hdr->poln_type, NULL, status);
    fits_update_key(pf->fptr, TINT, "FD_HAND", &(hdr->fd_hand), NULL, status);
    fits_update_key(pf->fptr, TDOUBLE, "FD_SANG", &(hdr->fd_sang), NULL, status);
    fits_update_key(pf->fptr, TDOUBLE, "FD_XYPH", &(hdr->fd_xyph), NULL, status);
    fits_update_key(pf->fptr, TINT, "BE_PHASE", &(hdr->be_phase), NULL, status);
    fits_update_key(pf->fptr, TSTRING, "DATE-OBS", hdr->date_obs, NULL, status);
    if (mode==fold && !strcmp("CAL",hdr->obs_mode)) 
        fits_update_key(pf->fptr, TSTRING, "OBS_MODE", hdr->obs_mode, 
                NULL, status);
    fits_update_key(pf->fptr, TDOUBLE, "OBSFREQ", &(hdr->fctr), NULL, status);
    fits_update_key(pf->fptr, TDOUBLE, "OBSBW", &(hdr->BW), NULL, status);
    fits_update_key(pf->fptr, TINT, "OBSNCHAN", &(hdr->orig_nchan), NULL, status);
    fits_update_key(pf->fptr, TDOUBLE, "CHAN_DM", &(hdr->chan_dm), NULL, status);
    fits_update_key(pf->fptr, TSTRING, "SRC_NAME", hdr->source, NULL, status);
    if (!strcmp("UNKNOWN", hdr->track_mode)) {
        printf("Warning!:  Unknown telescope tracking mode!\n");
    }
    fits_update_key(pf->fptr, TSTRING, "TRK_MODE", hdr->track_mode, NULL, status);
    // TODO: will need to change the following if we aren't tracking!
    fits_update_key(pf->fptr, TSTRING, "RA", hdr->ra_str, NULL, status);
    fits_update_key(pf->fptr, TSTRING, "DEC", hdr->dec_str, NULL, status);
    fits_update_key(pf->fptr, TSTRING, "STT_CRD1", hdr->ra_str, NULL, status);
    fits_update_key(pf->fptr, TSTRING, "STP_CRD1", hdr->ra_str, NULL, status);
    // TODO: update these at the end of the file or obs
    fits_update_key(pf->fptr, TSTRING, "STT_CRD2", hdr->dec_str, NULL, status);
    fits_update_key(pf->fptr, TSTRING, "STP_CRD2", hdr->dec_str, NULL, status);
    fits_update_key(pf->fptr, TDOUBLE, "BMAJ", &(hdr->beam_FWHM), NULL, status);
    fits_update_key(pf->fptr, TDOUBLE, "BMIN", &(hdr->beam_FWHM), NULL, status);
    if (strcmp("OFF", hdr->cal_mode)) {
        fits_update_key(pf->fptr, TDOUBLE, "CAL_FREQ", &(hdr->cal_freq), NULL, status);
        fits_update_key(pf->fptr, TDOUBLE, "CAL_DCYC", &(hdr->cal_dcyc), NULL, status);
        fits_update_key(pf->fptr, TDOUBLE, "CAL_PHS", &(hdr->cal_phs), NULL, status);
    }
    fits_update_key(pf->fptr, TDOUBLE, "SCANLEN", &(hdr->scanlen), NULL, status);
    itmp = (int) hdr->MJD_epoch;
    fits_update_key(pf->fptr, TINT, "STT_IMJD", &itmp, NULL, status);
    ldtmp = (hdr->MJD_epoch - (long double) itmp) * 86400.0L;   // in sec
    itmp = (int) ldtmp;
    fits_update_key(pf->fptr, TINT, "STT_SMJD", &itmp, NULL, status);
    ldtmp -= (long double) itmp;
    dtmp = (double) ldtmp;
    fits_update_key(pf->fptr, TDOUBLE, "STT_OFFS", &dtmp, NULL, status);
    fits_update_key(pf->fptr, TDOUBLE, "STT_LST", &(hdr->start_lst), NULL, status);

    // If fold mode, copy the parfile into the PSRFITS EPHEM table
    if (mode==fold) {
        if (strcmp("CAL",hdr->obs_mode)==0) {
            // CAL mode has no par file, or no par file given
            psrfits_remove_ephem(pf);
        } else if (fld->parfile[0]=='\0') {
            // No par file given
            fprintf(stderr, 
                    "psrfits_create warning:  "
                    "Fold mode selected, but no parfile given - "
                    "EPHEM table will be removed.\n"
                    );
            psrfits_remove_ephem(pf);
        } else {
            FILE *parfile = fopen(fld->parfile, "r");
            if (parfile==NULL) {
                fprintf(stderr, 
                        "psrfits_create warning:  "
                        "Error opening parfile %s - "
                        "EPHEM table will be removed.\n", fld->parfile
                        );
                psrfits_remove_ephem(pf);
            } else {
                psrfits_write_ephem(pf, parfile);
                fclose(parfile);
            }
        }
    }

    // Go to the SUBINT HDU
    fits_movnam_hdu(pf->fptr, BINARY_TBL, "SUBINT", 0, status);

    // Update the keywords that need it
    if (hdr->onlyI) {
        itmp = 1;
        fits_update_key(pf->fptr, TINT, "NPOL", &itmp, NULL, status);
    } else {
        fits_update_key(pf->fptr, TINT, "NPOL", &(hdr->npol), NULL, status);
    }
    if (!hdr->onlyI && !hdr->summed_polns) {
        // TODO:  These need to be updated for the real machine.
        if (hdr->npol==1)
            strcpy(ctmp, "AA");
        else if (hdr->npol==2)
            strcpy(ctmp, "AABB");
        else if (hdr->npol==4) {
            if (strncmp(hdr->poln_order, "AABBCRCI", 8)==0)
                strcpy(ctmp, hdr->poln_order);
            else
                strcpy(ctmp, "IQUV");
        }
        fits_update_key(pf->fptr, TSTRING, "POL_TYPE", ctmp, NULL, status);
    } else {
        fits_update_key(pf->fptr, TSTRING, "POL_TYPE", "AA+BB", NULL, status);
    }
    // TODO what does TBIN mean in fold mode?
    dtmp = hdr->dt * hdr->ds_time_fact;
    fits_update_key(pf->fptr, TDOUBLE, "TBIN", &dtmp, NULL, status);
    fits_update_key(pf->fptr, TINT, "NSUBOFFS", &(hdr->offset_subint), NULL, status);
    itmp = hdr->nchan / hdr->ds_freq_fact;
    fits_update_key(pf->fptr, TINT, "NCHAN", &itmp, NULL, status);
    dtmp = hdr->df * hdr->ds_freq_fact;
    fits_update_key(pf->fptr, TDOUBLE, "CHAN_BW", &dtmp, NULL, status);
    if (mode==search) {
        int out_nsblk = hdr->nsblk / hdr->ds_time_fact;
        itmp = 1;
        fits_update_key(pf->fptr, TINT, "NSBLK", &out_nsblk, NULL, status);
        fits_update_key(pf->fptr, TINT, "NBITS", &(hdr->nbits), NULL, status);
        fits_update_key(pf->fptr, TINT, "NBIN", &itmp, NULL, status);
    } else if (mode==fold) {
        itmp = 1;
        fits_update_key(pf->fptr, TINT, "NSBLK", &itmp, NULL, status);
        fits_update_key(pf->fptr, TINT, "NBITS", &itmp, NULL, status);
        fits_update_key(pf->fptr, TINT, "NBIN", &(hdr->nbin), NULL, status);
        fits_update_key(pf->fptr, TSTRING, "EPOCHS", "MIDTIME", NULL, status);
    }

    // Update the column sizes for the colums containing arrays
    {
        int out_npol = hdr->npol;
        int out_nchan = hdr->nchan / hdr->ds_freq_fact;
        if (hdr->onlyI) out_npol = 1;
        int out_nsblk = hdr->nsblk / hdr->ds_time_fact;

        fits_modify_vector_len(pf->fptr, 13, out_nchan, status); // DAT_FREQ
        fits_modify_vector_len(pf->fptr, 14, out_nchan, status); // DAT_WTS
        itmp = out_nchan * out_npol;
        fits_modify_vector_len(pf->fptr, 15, itmp, status); // DAT_OFFS
        fits_modify_vector_len(pf->fptr, 16, itmp, status); // DAT_SCL
        
        if (mode==search) {
            lltmp = out_nsblk;
            lltmp = (lltmp * hdr->nbits * out_nchan * out_npol) / 8L;
        } else if (mode==fold)
            lltmp = (hdr->nbin * out_nchan * out_npol);
        fits_modify_vector_len(pf->fptr, 17, lltmp, status); // DATA
        // Update the TDIM field for the data column
        if (mode==search)
            sprintf(ctmp, "(1,%d,%d,%d)", out_nchan, out_npol, out_nsblk);
        else if (mode==fold) 
            sprintf(ctmp, "(%d,%d,%d,1)", hdr->nbin, out_nchan, out_npol);
        fits_update_key(pf->fptr, TSTRING, "TDIM17", ctmp, NULL, status);
    }

    fits_flush_file(pf->fptr, status);
    
    return *status;
}
int main(int argc, char *argv[])
{
    int numfiles, ii, numrows, rownum, ichan, itsamp, datidx;
    int spec_per_row, status, maxrows;
    unsigned long int maxfilesize;
    float offset, scale, datum, packdatum, maxval, fulltsubint;
    float *datachunk;
    FILE **infiles;
    struct psrfits pfin, pfout;
    Cmdline *cmd;
    fitsfile *infits, *outfits;
    char outfilename[128], templatename[128], tform[8];
    char *pc1, *pc2;
    int first = 1, dummy = 0, nclipped;
    short int *inrowdata;
    unsigned char *outrowdata;

    if (argc == 1) {
        Program = argv[0];
        usage();
        exit(1);
    }
    // Parse the command line using the excellent program Clig
    cmd = parseCmdline(argc, argv);
    numfiles = cmd->argc;
    infiles = (FILE **) malloc(numfiles * sizeof(FILE *));

    //Set the max. total size (in bytes) of all rows in an output file,
    //leaving some room for PSRFITS header
    maxfilesize = (unsigned long int)(cmd->numgb * GB);
    maxfilesize = maxfilesize - 1000*KB;
    //fprintf(stderr,"cmd->numgb: %f maxfilesize: %ld\n",cmd->numgb,maxfilesize);

#ifdef DEBUG
    showOptionValues();
#endif

    printf("\n         PSRFITS 16-bit to 4-bit Conversion Code\n");
    printf("         by J. Deneva, S. Ransom, & S. Chatterjee\n\n");

    // Open the input files
    status = 0;                 //fits_close segfaults if this is not initialized
    printf("Reading input data from:\n");
    for (ii = 0; ii < numfiles; ii++) {
        printf("  '%s'\n", cmd->argv[ii]);

        //Get the file basename and number from command-line argument
        //(code taken from psrfits2fil)
        pc2 = strrchr(cmd->argv[ii], '.');      // at .fits
        *pc2 = 0;               // terminate string
        pc1 = pc2 - 1;
        while ((pc1 >= cmd->argv[ii]) && isdigit(*pc1))
            pc1--;
        if (pc1 <= cmd->argv[ii]) {     // need at least 1 char before filenum
            puts("Illegal input filename. must have chars before the filenumber");
            exit(1);
        }
        pc1++;                  // we were sitting on "." move to first digit
        pfin.filenum = atoi(pc1);
        pfin.fnamedigits = pc2 - pc1;   // how many digits in filenumbering scheme.
        *pc1 = 0;               // null terminate the basefilename
        strcpy(pfin.basefilename, cmd->argv[ii]);
        pfin.initialized = 0;   // set to 1 in  psrfits_open()
        pfin.status = 0;
        //(end of code taken from psrfits2fil)

        //Open the existing psrfits file
        if (psrfits_open(&pfin, READONLY) != 0) {
            fprintf(stderr, "error opening file\n");
            fits_report_error(stderr, pfin.status);
            exit(1);
        }
        // Create the subint arrays
        if (first) {
            pfin.sub.dat_freqs = (float *) malloc(sizeof(float) * pfin.hdr.nchan);
            pfin.sub.dat_weights = (float *) malloc(sizeof(float) * pfin.hdr.nchan);
            pfin.sub.dat_offsets =
                (float *) malloc(sizeof(float) * pfin.hdr.nchan * pfin.hdr.npol);
            pfin.sub.dat_scales =
                (float *) malloc(sizeof(float) * pfin.hdr.nchan * pfin.hdr.npol);
            //first is set to 0 after data buffer allocation further below
        }

        infits = pfin.fptr;
        spec_per_row = pfin.hdr.nsblk;
	fits_read_key(infits, TINT, "NAXIS2", &dummy, NULL, &status);
	pfin.tot_rows = dummy;
        numrows = dummy;

	//If dealing with 1st input file, create output template
	if (ii == 0) {
	  sprintf(templatename, "%s.template.fits",cmd->outfile);
	  fits_create_file(&outfits, templatename, &status);
	  //fprintf(stderr,"pfin.basefilename: %s\n", pfin.basefilename);
	  //fprintf(stderr,"status: %d\n", status);
	  
	  //Instead of copying HDUs one by one, can move to the SUBINT
	  //HDU, and copy all the HDUs preceding it
	  fits_movnam_hdu(infits, BINARY_TBL, "SUBINT", 0, &status);
	  fits_copy_file(infits, outfits, 1, 0, 0, &status);
	  
	  //Copy the SUBINT table header
	  fits_copy_header(infits, outfits, &status);
	  fits_flush_buffer(outfits, 0, &status);
	  
	  //Set NAXIS2 in the output SUBINT table to 0 b/c we haven't 
	  //written any rows yet
	  dummy = 0;
	  fits_update_key(outfits, TINT, "NAXIS2", &dummy, NULL, &status);
	  
	  //Edit the NBITS key
	  if (DEBUG) {
	    dummy = 8;
	    fits_update_key(outfits, TINT, "NBITS", &dummy, NULL, &status);
	  } else {
	    fits_update_key(outfits, TINT, "NBITS", &(cmd->numbits), NULL,
			    &status);
	  }
	  
	  //Edit the TFORM17 column: # of data bytes per row 
	  //fits_get_colnum(outfits,1,"DATA",&dummy,&status);
	  if (DEBUG)
	    sprintf(tform, "%dB",
		    pfin.hdr.nsblk * pfin.hdr.nchan * pfin.hdr.npol);
	  else
	    sprintf(tform, "%dB", pfin.hdr.nsblk * pfin.hdr.nchan *
		    pfin.hdr.npol * cmd->numbits / 8);
	  
	  fits_update_key(outfits, TSTRING, "TTYPE17", "DATA", NULL, &status);
	  fits_update_key(outfits, TSTRING, "TFORM17", tform, NULL, &status);
	  
	  //Edit NAXIS1: row width in bytes
	  fits_read_key(outfits, TINT, "NAXIS1", &dummy, NULL, &status);
	  if (DEBUG) {
	    dummy = dummy - pfin.hdr.nsblk * pfin.hdr.nchan *
	      pfin.hdr.npol * (pfin.hdr.nbits - 8) / 8;
	  } else {
	    dummy = dummy - pfin.hdr.nsblk * pfin.hdr.nchan *
	      pfin.hdr.npol * (pfin.hdr.nbits - cmd->numbits) / 8;
	  }
	  fits_update_key(outfits, TINT, "NAXIS1", &dummy, NULL, &status);
	  
	  //Set the max # of rows per file, based on the requested 
	  //output file size
	  maxrows = maxfilesize / dummy;
	  //fprintf(stderr,"maxrows: %d\n",maxrows);

	  fits_close_file(outfits, &status);
	  
	  rownum = 0;
	}
	
        while (psrfits_read_subint(&pfin, first) == 0) {
	  fprintf(stderr, "Working on row %d\n", ++rownum);
	  
	  //If this is the first row, store the length of a full subint
	  if (ii == 0 && rownum == 1)
	    fulltsubint = pfin.sub.tsubint;

	  //If this is the last row and it's partial, drop it.
	  //(It's pfin.rownum-1 below because the rownum member of the psrfits struct seems to be intended to indicate at the *start* of what row we are, i.e. a row that has not yet been read. In contrast, pfout.rownum indicates how many rows have been written, i.e. at the *end* of what row we are in the output.)
	  
	  if (pfin.rownum-1 == numrows && fabs(pfin.sub.tsubint - fulltsubint) > pfin.hdr.dt) {
	    fprintf(stderr,
		    "Dropping partial row of length %f s (full row is %f s)\n",
		    pfin.sub.tsubint, fulltsubint);
	    break;
	  }
	  
	  //If we just read in the 1st row, or if we already wrote the last row in the current output file, create a new output file
	  if ((ii == 0 && rownum == 1) || pfout.rownum == maxrows) {
	    //Create new output file from the template
	    pfout.fnamedigits = pfin.fnamedigits;
	    if(ii == 0)
	      pfout.filenum = pfin.filenum;
	    else
	      pfout.filenum++;
	    
	    sprintf(outfilename, "%s.%0*d.fits", cmd->outfile, pfout.fnamedigits, pfout.filenum);
	    fits_create_template(&outfits, outfilename, templatename, &status);
	    //fprintf(stderr,"After fits_create_template, status: %d\n",status);
	    fits_close_file(outfits, &status);
	    
	    //Now reopen the file so that the pfout structure is initialized
	    pfout.status = 0;
	    pfout.initialized = 0;
	    
	    sprintf(pfout.basefilename, "%s.", cmd->outfile);
	    
            if (psrfits_open(&pfout, READWRITE) != 0) {
	      fprintf(stderr, "error opening file\n");
	      fits_report_error(stderr, pfout.status);
	      exit(1);
            }
            outfits = pfout.fptr;
            maxval = pow(2, cmd->numbits) - 1;
	    pfout.rows_per_file = maxrows;
	    
            //fprintf(stderr, "maxval: %f\n", maxval);
	    //fprintf(stderr, "pfout.rows_per_file: %d\n",pfout.rows_per_file);
	    
            //These are not initialized in psrfits_open but are needed 
            //in psrfits_write_subint (not obvious what are the corresponding 
            //fields in any of the psrfits table headers)
            pfout.hdr.ds_freq_fact = 1;
            pfout.hdr.ds_time_fact = 1;
	  }

            //Copy the subint struct from pfin to pfout, but correct 
            //elements that are not the same 
            pfout.sub = pfin.sub;       //this copies array pointers too
            pfout.sub.bytes_per_subint =
                pfin.sub.bytes_per_subint * pfout.hdr.nbits / pfin.hdr.nbits;
            pfout.sub.dataBytesAlloced = pfout.sub.bytes_per_subint;
            pfout.sub.FITS_typecode = TBYTE;

            if (first) {
                //Allocate scaling buffer and output buffer
                datachunk = gen_fvect(spec_per_row);
                outrowdata = gen_bvect(pfout.sub.bytes_per_subint);

                first = 0;
            }
            pfout.sub.data = outrowdata;

            inrowdata = (short int *) pfin.sub.data;
            nclipped = 0;

            // Loop over all the channels:
            for (ichan = 0; ichan < pfout.hdr.nchan * pfout.hdr.npol; ichan++) {
                // Populate datachunk[] by picking out all time samples for ichan
                for (itsamp = 0; itsamp < spec_per_row; itsamp++)
                    datachunk[itsamp] = (float) (inrowdata[ichan + itsamp *
                                                           pfout.hdr.nchan *
                                                           pfout.hdr.npol]);

                // Compute the statistics here, and put the offsets and scales in
                // pf.sub.dat_offsets[] and pf.sub.dat_scales[]

                if (rescale(datachunk, spec_per_row, cmd->numbits, &offset, &scale)
                    != 0) {
                    printf("Rescale routine failed!\n");
                    return (-1);
                }
                pfout.sub.dat_offsets[ichan] = offset;
                pfout.sub.dat_scales[ichan] = scale;

                // Since we have the offset and scale ready, rescale the data:
                for (itsamp = 0; itsamp < spec_per_row; itsamp++) {
                    datum = (scale == 0.0) ? 0.0 :
                        roundf((datachunk[itsamp] - offset) / scale);
                    if (datum < 0.0) {
                        datum = 0;
                        nclipped++;
                    } else if (datum > maxval) {
                        datum = maxval;
                        nclipped++;
                    }

                    inrowdata[ichan + itsamp * pfout.hdr.nchan * pfout.hdr.npol] =
                        (short int) datum;

                }
                // Now inrowdata[ichan] contains rescaled ints.
            }

            // Then do the conversion and store the
            // results in pf.sub.data[] 
            if (cmd->numbits == 8 || DEBUG) {
                for (itsamp = 0; itsamp < spec_per_row; itsamp++) {
                    datidx = itsamp * pfout.hdr.nchan * pfout.hdr.npol;
                    for (ichan = 0; ichan < pfout.hdr.nchan * pfout.hdr.npol;
                         ichan++, datidx++) {
                        pfout.sub.data[datidx] = (unsigned char) inrowdata[datidx];
                    }
                }
            } else if (cmd->numbits == 4) {
                for (itsamp = 0; itsamp < spec_per_row; itsamp++) {
                    datidx = itsamp * pfout.hdr.nchan * pfout.hdr.npol;
                    for (ichan = 0; ichan < pfout.hdr.nchan * pfout.hdr.npol;
                         ichan += 2, datidx += 2) {

                        packdatum = inrowdata[datidx] * 16 + inrowdata[datidx + 1];
                        pfout.sub.data[datidx / 2] = (unsigned char) packdatum;
                    }
                }
            } else {
                fprintf(stderr, "Only 4 or 8-bit output formats supported.\n");
                fprintf(stderr, "Bits per sample requested: %d\n", cmd->numbits);
                exit(1);
            }


            //pfout.sub.offs = (pfout.tot_rows+0.5) * pfout.sub.tsubint;
            fprintf(stderr, "nclipped: %d fraction clipped: %f\n", nclipped,
                    (float) nclipped / (pfout.hdr.nchan * pfout.hdr.npol *
                                        pfout.hdr.nsblk));

            // Now write the row. 
            status = psrfits_write_subint(&pfout);
            if (status) {
                printf("\nError (%d) writing PSRFITS...\n\n", status);
                break;
            }

	    //If current output file has reached the max # of rows, close it
	    if (pfout.rownum == maxrows)
	      fits_close_file(outfits, &status);
        }

        //Close the files 
        fits_close_file(infits, &status);
    }

    fits_close_file(outfits, &status);

    // Free the structure arrays too...
    free(datachunk);
    free(infiles);

    free(pfin.sub.dat_freqs);
    free(pfin.sub.dat_weights);
    free(pfin.sub.dat_offsets);
    free(pfin.sub.dat_scales);

    free(pfin.sub.data);
    free(pfout.sub.data);
    free(pfin.sub.stat);

    return 0;
}