Example #1
0
void get_PSRFITS_subint(float *fdata, unsigned char *cdata, struct spectra_info *s)
{
    unsigned char *ctmp = cdata;
    int ii, status = 0, anynull;
    int numtoread = s->samples_per_subint;

    // The following allows us to read byte-packed data
    if (s->bits_per_sample < 8) {
        numtoread = (s->samples_per_subint * s->bits_per_sample) / 8;
        ctmp = gen_bvect(numtoread);
    }
    // or 16-bit data that is listed as being bytes
    if (s->bits_per_sample == 16 && s->FITS_typecode == 11)
        numtoread = s->samples_per_subint * 2;

    // Read the weights, offsets, and scales if required
    if (s->apply_weight)
        fits_read_col(s->fitsfiles[cur_file], TFLOAT, s->dat_wts_col, cur_subint, 1L,
                      s->num_channels, 0, weights, &anynull, &status);
    if (s->apply_offset)
        fits_read_col(s->fitsfiles[cur_file], TFLOAT, s->dat_offs_col, cur_subint,
                      1L, s->num_channels * s->num_polns, 0, offsets, &anynull,
                      &status);
    if (s->apply_scale)
        fits_read_col(s->fitsfiles[cur_file], TFLOAT, s->dat_scl_col, cur_subint, 1L,
                      s->num_channels * s->num_polns, 0, scales, &anynull, &status);

    // Now actually read the subint into the temporary buffer
    fits_read_col(s->fitsfiles[cur_file], s->FITS_typecode,
                  s->data_col, cur_subint, 1L, numtoread,
                  0, ctmp, &anynull, &status);

    if (status) {
        fprintf(stderr, "Error!:  Problem reading record from PSRFITS data file\n"
                "\tfilename = '%s', subint = %d.  FITS status = %d.  Exiting.\n",
                s->filenames[cur_file], cur_subint, status);
        exit(1);
    }
    // The following converts that byte-packed data into bytes
    if (s->bits_per_sample == 4) {
#ifdef _OPENMP
#pragma omp parallel for default(none) shared(numtoread,cdata,ctmp)
#endif
        for (ii = 0; ii < numtoread; ii++) {
            const unsigned char uctmp = ctmp[ii];
            const int jj = 2 * ii;
            cdata[jj] = uctmp >> 4;
            cdata[jj + 1] = uctmp & 0x0F;
        }
    } else if (s->bits_per_sample == 2) {
Example #2
0
void read_PSRFITS_files(struct spectra_info *s)
// Read and convert PSRFITS information from a group of files 
// and place the resulting info into a spectra_info structure.
{
    int IMJD, SMJD, itmp, ii, status = 0;
    double OFFS, dtmp;
    long double MJDf;
    char ctmp[80], comment[120];
    
    s->datatype = PSRFITS;
    s->fitsfiles = (fitsfile **)malloc(sizeof(fitsfile *) * s->num_files);
    s->start_subint = gen_ivect(s->num_files);
    s->num_subint = gen_ivect(s->num_files);
    s->start_spec = (long long *)malloc(sizeof(long long) * s->num_files);
    s->num_spec = (long long *)malloc(sizeof(long long) * s->num_files);
    s->num_pad = (long long *)malloc(sizeof(long long) * s->num_files);
    s->start_MJD = (long double *)malloc(sizeof(long double) * s->num_files);
    s->N = 0;
    s->num_beams = 1;
    s->get_rawblock = &get_PSRFITS_rawblock;
    s->offset_to_spectra = &offset_to_PSRFITS_spectra;

    // By default, don't flip the band.  But don't change
    // the input value if it is aleady set to flip the band always
    if (s->apply_flipband==-1) s->apply_flipband = 0;

    // Step through the other files
    for (ii = 0 ; ii < s->num_files ; ii++) {

        // Is the file a PSRFITS file?
        if (!is_PSRFITS(s->filenames[ii])) {
            fprintf(stderr, 
                    "\nError!  File '%s' does not appear to be PSRFITS!\n", 
                    s->filenames[ii]);
            exit(1);
        }
        
        // Open the PSRFITS file
        fits_open_file(&(s->fitsfiles[ii]), s->filenames[ii], READONLY, &status);

        // Is the data in search mode?
        fits_read_key(s->fitsfiles[ii], TSTRING, "OBS_MODE", ctmp, comment, &status);
        // Quick fix for Parkes DFB data (SRCH?  why????)...
        if (strcmp("SRCH", ctmp)==0) {
            strncpy(ctmp, "SEARCH", 40);
        }
        if (strcmp(ctmp, "SEARCH")) {
            fprintf(stderr, 
                    "\nError!  File '%s' does not contain SEARCH-mode data!\n", 
                    s->filenames[ii]);
            exit(1);
        }

        // Now get the stuff we need from the primary HDU header
        fits_read_key(s->fitsfiles[ii], TSTRING, "TELESCOP", ctmp, comment, &status); \
        // Quick fix for MockSpec data...
        if (strcmp("ARECIBO 305m", ctmp)==0) {
            strncpy(ctmp, "Arecibo", 40);
        }
        // Quick fix for Parkes DFB data...
        {
            char newctmp[80];

            // Copy ctmp first since strlower() is in-place
            strcpy(newctmp, ctmp);
            if (strcmp("parkes", strlower(remove_whitespace(newctmp)))==0) {
                strncpy(ctmp, "Parkes", 40);
            }
        }
        if (status) {
            printf("Error %d reading key %s\n", status, "TELESCOP");
            if (ii==0) s->telescope[0]='\0';
            if (status==KEY_NO_EXIST) status=0;
        } else {
            if (ii==0) strncpy(s->telescope, ctmp, 40);
            else if (strcmp(s->telescope, ctmp)!=0)
                printf("Warning!:  %s values don't match for files 0 and %d!\n",
                       "TELESCOP", ii);
        }

        get_hdr_string("OBSERVER", s->observer);
        get_hdr_string("SRC_NAME", s->source);
        get_hdr_string("FRONTEND", s->frontend);
        get_hdr_string("BACKEND", s->backend);
        get_hdr_string("PROJID", s->project_id);
        get_hdr_string("DATE-OBS", s->date_obs);
        get_hdr_string("FD_POLN", s->poln_type);
        get_hdr_string("RA", s->ra_str);
        get_hdr_string("DEC", s->dec_str);
        get_hdr_double("OBSFREQ", s->fctr);
        get_hdr_int("OBSNCHAN", s->orig_num_chan);
        get_hdr_double("OBSBW", s->orig_df);
        //get_hdr_double("CHAN_DM", s->chan_dm);
        get_hdr_double("BMIN", s->beam_FWHM);

        /* This is likely not in earlier versions of PSRFITS so */
        /* treat it a bit differently                           */
        fits_read_key(s->fitsfiles[ii], TDOUBLE, "CHAN_DM", 
                      &(s->chan_dm), comment, &status);
        if (status==KEY_NO_EXIST) {
            status = 0;
            s->chan_dm = 0.0;
        }

        // Don't use the macros unless you are using the struct!
        fits_read_key(s->fitsfiles[ii], TINT, "STT_IMJD", &IMJD, comment, &status);
        s->start_MJD[ii] = (long double) IMJD;
        fits_read_key(s->fitsfiles[ii], TINT, "STT_SMJD", &SMJD, comment, &status);
        fits_read_key(s->fitsfiles[ii], TDOUBLE, "STT_OFFS", &OFFS, comment, &status);
        s->start_MJD[ii] += ((long double) SMJD + (long double) OFFS) / SECPERDAY;

        // Are we tracking?
        fits_read_key(s->fitsfiles[ii], TSTRING, "TRK_MODE", ctmp, comment, &status);
        itmp = (strcmp("TRACK", ctmp)==0) ? 1 : 0;
        if (ii==0) s->tracking = itmp;
        else if (s->tracking != itmp)
            printf("Warning!:  TRK_MODE values don't match for files 0 and %d!\n", ii);

        // Now switch to the SUBINT HDU header
        fits_movnam_hdu(s->fitsfiles[ii], BINARY_TBL, "SUBINT", 0, &status);
        get_hdr_double("TBIN", s->dt);
        get_hdr_int("NCHAN", s->num_channels);
        get_hdr_int("NPOL", s->num_polns);
        get_hdr_string("POL_TYPE", s->poln_order);
        fits_read_key(s->fitsfiles[ii], TINT, "NCHNOFFS", &itmp, comment, &status);
        if (itmp > 0)
            printf("Warning!:  First freq channel is not 0 in file %d!\n", ii);
        get_hdr_int("NSBLK", s->spectra_per_subint);
        get_hdr_int("NBITS", s->bits_per_sample);
        fits_read_key(s->fitsfiles[ii], TINT, "NAXIS2", 
                      &(s->num_subint[ii]), comment, &status);
        fits_read_key(s->fitsfiles[ii], TINT, "NSUBOFFS", 
                      &(s->start_subint[ii]), comment, &status);
        s->time_per_subint = s->dt * s->spectra_per_subint;

        /* This is likely not in earlier versions of PSRFITS so */
        /* treat it a bit differently                           */
        fits_read_key(s->fitsfiles[ii], TFLOAT, "ZERO_OFF", 
                      &(s->zero_offset), comment, &status);
        if (status==KEY_NO_EXIST) {
            status = 0;
            s->zero_offset = 0.0;
        }
        s->zero_offset = fabs(s->zero_offset);

        // Get the time offset column info and the offset for the 1st row
        {
            double offs_sub;
            int colnum, anynull, numrows;

            // Identify the OFFS_SUB column number
            fits_get_colnum(s->fitsfiles[ii], 0, "OFFS_SUB", &colnum, &status);
            if (status==COL_NOT_FOUND) {
                printf("Warning!:  Can't find the OFFS_SUB column!\n");
                status = 0; // Reset status
            } else {
                if (ii==0) {
                    s->offs_sub_col = colnum;
                } else if (colnum != s->offs_sub_col) {
                    printf("Warning!:  OFFS_SUB column changes between files!\n");
                }
            }

            // Read the OFFS_SUB column value for the 1st row
            fits_read_col(s->fitsfiles[ii], TDOUBLE,
                          s->offs_sub_col, 1L, 1L, 1L,
                          0, &offs_sub, &anynull, &status);

            numrows = (int)((offs_sub - 0.5 * s->time_per_subint) /
                            s->time_per_subint + 1e-7);
            // Check to see if any rows have been deleted or are missing
            if (numrows > s->start_subint[ii]) {
                printf("Warning: NSUBOFFS reports %d previous rows\n"
                       "         but OFFS_SUB implies %d.  Using OFFS_SUB.\n"
                       "         Will likely be able to correct for this.\n",
                       s->start_subint[ii], numrows);
            }
            s->start_subint[ii] = numrows;
        }

        // This is the MJD offset based on the starting subint number
        MJDf = (s->time_per_subint * s->start_subint[ii]) / SECPERDAY;
        // The start_MJD values should always be correct
        s->start_MJD[ii] += MJDf;

        // Compute the starting spectra from the times
        MJDf = s->start_MJD[ii] - s->start_MJD[0];
        if (MJDf < 0.0) {
            fprintf(stderr, "Error!: File %d seems to be from before file 0!\n", ii); 
            exit(1);
        }
        s->start_spec[ii] = (long long)(MJDf * SECPERDAY / s->dt + 0.5);

        // Now pull stuff from the other columns
        {
            float ftmp;
            long repeat, width;
            int colnum, anynull;
            
            // Identify the data column and the data type
            fits_get_colnum(s->fitsfiles[ii], 0, "DATA", &colnum, &status);
            if (status==COL_NOT_FOUND) {
                printf("Warning!:  Can't find the DATA column!\n");
                status = 0; // Reset status
            } else {
                if (ii==0) {
                    s->data_col = colnum;
                    fits_get_coltype(s->fitsfiles[ii], colnum, &(s->FITS_typecode), 
                                     &repeat, &width, &status);
                } else if (colnum != s->data_col) {
                    printf("Warning!:  DATA column changes between files!\n");
                }
            }
            
            // Telescope azimuth
            fits_get_colnum(s->fitsfiles[ii], 0, "TEL_AZ", &colnum, &status);
            if (status==COL_NOT_FOUND) {
                s->azimuth = 0.0;
                status = 0; // Reset status
            } else {
                fits_read_col(s->fitsfiles[ii], TFLOAT, colnum, 
                              1L, 1L, 1L, 0, &ftmp, &anynull, &status);
                if (ii==0) s->azimuth = (double) ftmp;
            }
            
            // Telescope zenith angle
            fits_get_colnum(s->fitsfiles[ii], 0, "TEL_ZEN", &colnum, &status);
            if (status==COL_NOT_FOUND) {
                s->zenith_ang = 0.0;
                status = 0; // Reset status
            } else {
                fits_read_col(s->fitsfiles[ii], TFLOAT, colnum, 
                              1L, 1L, 1L, 0, &ftmp, &anynull, &status);
                if (ii==0) s->zenith_ang = (double) ftmp;
            }
            
            // Observing frequencies
            fits_get_colnum(s->fitsfiles[ii], 0, "DAT_FREQ", &colnum, &status);
            if (status==COL_NOT_FOUND) {
                printf("Warning!:  Can't find the channel freq column!\n");
                status = 0; // Reset status
            } else {
                int jj;
                float *freqs = (float *)malloc(sizeof(float) * s->num_channels);
                fits_read_col(s->fitsfiles[ii], TFLOAT, colnum, 1L, 1L, 
                              s->num_channels, 0, freqs, &anynull, &status);
                
                if (ii==0) {
                    s->df = freqs[1]-freqs[0];
                    s->lo_freq = freqs[0];
                    s->hi_freq = freqs[s->num_channels-1];
                    // Now check that the channel spacing is the same throughout
                    for (jj = 0 ; jj < s->num_channels - 1 ; jj++) {
                        ftmp = freqs[jj+1] - freqs[jj];
                        if (fabs(ftmp - s->df) > 1e-7)
                            printf("Warning!:  Channel spacing changes in file %d!\n", ii);
                    }
                } else {
                    ftmp = fabs(s->df-(freqs[1]-freqs[0]));
                    if (ftmp > 1e-7)
                        printf("Warning!:  Channel spacing changes between files!\n");
                    ftmp = fabs(s->lo_freq-freqs[0]);
                    if (ftmp > 1e-7)
                        printf("Warning!:  Low channel changes between files!\n");
                    ftmp = fabs(s->hi_freq-freqs[s->num_channels-1]);
                    if (ftmp > 1e-7)
                        printf("Warning!:  High channel changes between files!\n");
                }
                free(freqs);
            }
            
            // Data weights
            fits_get_colnum(s->fitsfiles[ii], 0, "DAT_WTS", &colnum, &status);
            if (status==COL_NOT_FOUND) {
                printf("Warning!:  Can't find the channel weights!\n");
                status = 0; // Reset status
            } else {
                if (s->apply_weight < 0) { // Use the data to decide
                    int jj;
                    if (ii==0) {
                        s->dat_wts_col = colnum;
                    } else if (colnum != s->dat_wts_col) {
                        printf("Warning!:  DAT_WTS column changes between files!\n");
                    }
                    float *fvec = (float *)malloc(sizeof(float) * s->num_channels);
                    fits_read_col(s->fitsfiles[ii], TFLOAT, s->dat_wts_col, 1L, 1L, 
                                  s->num_channels, 0, fvec, &anynull, &status);
                    for (jj = 0 ; jj < s->num_channels ; jj++) {
                        // If the weights are not 1, apply them
                        if (fvec[jj] != 1.0) {
                            s->apply_weight = 1;
                            break;
                        }
                    }
                    free(fvec);
                }
                if (s->apply_weight < 0) s->apply_weight = 0;  // not needed
            }
            
            // Data offsets
            fits_get_colnum(s->fitsfiles[ii], 0, "DAT_OFFS", &colnum, &status);
            if (status==COL_NOT_FOUND) {
                printf("Warning!:  Can't find the channel offsets!\n");
                status = 0; // Reset status
            } else {
                if (s->apply_offset < 0) { // Use the data to decide
                    int jj;
                    if (ii==0) {
                        s->dat_offs_col = colnum;
                    } else if (colnum != s->dat_offs_col) {
                        printf("Warning!:  DAT_OFFS column changes between files!\n");
                    }
                    float *fvec = (float *)malloc(sizeof(float) * 
                                                  s->num_channels * s->num_polns);
                    fits_read_col(s->fitsfiles[ii], TFLOAT, s->dat_offs_col, 1L, 1L, 
                                  s->num_channels * s->num_polns, 
                                  0, fvec, &anynull, &status);
                    for (jj = 0 ; jj < s->num_channels * s->num_polns ; jj++) {
                        // If the offsets are not 0, apply them
                        if (fvec[jj] != 0.0) {
                            s->apply_offset = 1;
                            break;
                        }
                    }
                    free(fvec);
                }
                if (s->apply_offset < 0) s->apply_offset = 0; // not needed
            }
            
            // Data scalings
            fits_get_colnum(s->fitsfiles[ii], 0, "DAT_SCL", &colnum, &status);
            if (status==COL_NOT_FOUND) {
                printf("Warning!:  Can't find the channel scalings!\n");
                status = 0; // Reset status
            } else {
                if (s->apply_scale < 0) { // Use the data to decide
                    int jj;
                    if (ii==0) {
                        s->dat_scl_col = colnum;
                    } else if (colnum != s->dat_scl_col) {
                        printf("Warning!:  DAT_SCL column changes between files!\n");
                    }
                    float *fvec = (float *)malloc(sizeof(float) * 
                                                  s->num_channels * s->num_polns);
                    fits_read_col(s->fitsfiles[ii], TFLOAT, colnum, 1L, 1L, 
                                  s->num_channels * s->num_polns, 
                                  0, fvec, &anynull, &status);
                    for (jj = 0 ; jj < s->num_channels * s->num_polns ; jj++) {
                        // If the scales are not 1, apply them
                        if (fvec[jj] != 1.0) {
                            s->apply_scale = 1;
                            break;
                        }
                    }
                    free(fvec);
                }
                if (s->apply_scale < 0) s->apply_scale = 0; // not needed
            }
        }
        
        // Compute the samples per file and the amount of padding
        // that the _previous_ file has
        s->num_pad[ii] = 0;
        s->num_spec[ii] = s->spectra_per_subint * s->num_subint[ii];
        if (ii > 0) {
            if (s->start_spec[ii] > s->N) { // Need padding
                s->num_pad[ii-1] = s->start_spec[ii] - s->N;
                s->N += s->num_pad[ii-1];
            }
        }
        s->N += s->num_spec[ii];
    }

    // Convert the position strings into degrees
    {
        int d, h, m;
        double sec;
        ra_dec_from_string(s->ra_str, &h, &m, &sec);
        s->ra2000 = hms2rad(h, m, sec) * RADTODEG;
        ra_dec_from_string(s->dec_str, &d, &m, &sec);
        s->dec2000 = dms2rad(d, m, sec) * RADTODEG;
    }

    // Are the polarizations summed?
    if ((strncmp("AA+BB", s->poln_order, 5)==0) ||
        (strncmp("INTEN", s->poln_order, 5)==0))
        s->summed_polns = 1;
    else
        s->summed_polns = 0;

    // Calculate some others
    s->T = s->N * s->dt;
    s->orig_df /= (double) s->orig_num_chan;
    s->samples_per_spectra = s->num_polns * s->num_channels;
    // Note:  the following is the number of bytes that will be in
    //        the returned array from CFITSIO.
    //        CFITSIO turns bits into bytes when FITS_typecode=1
    //        and we turn 2-bits or 4-bits into bytes if bits_per_sample < 8
    if (s->bits_per_sample < 8)
        s->bytes_per_spectra = s->samples_per_spectra;
    else
        s->bytes_per_spectra = (s->bits_per_sample * s->samples_per_spectra) / 8;
    s->samples_per_subint = s->samples_per_spectra * s->spectra_per_subint;
    s->bytes_per_subint = s->bytes_per_spectra * s->spectra_per_subint;
    
    // Flip the band?
    if (s->hi_freq < s->lo_freq) {
        float ftmp = s->hi_freq;
        s->hi_freq = s->lo_freq;
        s->lo_freq = ftmp;
        s->df *= -1.0;
        s->apply_flipband = 1;
    }
    // Compute the bandwidth
    s->BW = s->num_channels * s->df;

    // Flip the bytes for Parkes FB_1BIT data
    if (s->bits_per_sample==1 &&
        strcmp(s->telescope, "Parkes")==0 &&
        strcmp(s->backend, "FB_1BIT")==0) {
        printf("Flipping bit ordering since Parkes FB_1BIT data.\n");
        s->flip_bytes = 1;
    } else {
        s->flip_bytes = 0;
    }

    // Allocate the buffers
    cdatabuffer = gen_bvect(s->bytes_per_subint);
    // Following is twice as big because we use it as a ringbuffer too
    fdatabuffer = gen_fvect(2 * s->spectra_per_subint * s->num_channels);
    s->padvals = gen_fvect(s->num_channels);
    for (ii = 0 ; ii < s->num_channels ; ii++)
        s->padvals[ii] = 0.0;
    offsets = gen_fvect(s->num_channels * s->num_polns);
    scales = gen_fvect(s->num_channels * s->num_polns);
    weights = gen_fvect(s->num_channels);
    // Initialize these if we won't be reading them from the file
    if (s->apply_offset==0) 
        for (ii = 0 ; ii < s->num_channels * s->num_polns ; ii++)
            offsets[ii] = 0.0;
    if (s->apply_scale==0)
        for (ii = 0 ; ii < s->num_channels * s->num_polns ; ii++)
            scales[ii] = 1.0;
    if (s->apply_weight==0)
        for (ii = 0 ; ii < s->num_channels ; ii++)
            weights[ii] = 1.0;
}
Example #3
0
void fill_psrfits_struct(int numwapps, int numbits, struct HEADERP *h,
                         struct wappinfo *w, struct psrfits *pf)
{
    int slen, ii;
    char *cptr;

    pf->filenum = 0;            // Crucial for initialization
    pf->hdr.nsblk = (int) (1.0 / w->dt);        // _might_ be a problem...

    // Now set values for our hdrinfo structure
    strcpy(pf->hdr.telescope, "Arecibo");
    cptr = get_hdr_string(h, "obs_type", &slen);
    if (strncmp("PULSAR_SEARCH", cptr, slen) == 0) {
        strcpy(pf->hdr.obs_mode, "SEARCH");
    } else {
        printf("Error:  Wapp data is not in search format!\n\n");
        exit(1);
    }
    strcpy(pf->hdr.backend, "WAPP");
    cptr = get_hdr_string(h, "frontend", &slen);
    if(cptr != NULL)
      strncpy(pf->hdr.frontend, cptr, slen);
    else
      strncpy(pf->hdr.frontend, "alfa", 4);
    cptr = get_hdr_string(h, "observers", &slen);
    strncpy(pf->hdr.observer, cptr, slen);
    cptr = get_hdr_string(h, "project_id", &slen);
    strncpy(pf->hdr.project_id, cptr, slen);
    cptr = get_hdr_string(h, "src_name", &slen);
    strncpy(pf->hdr.source, cptr, slen);
    strcpy(pf->hdr.date_obs, w->date_obs);
    pf->hdr.scanlen = get_hdr_double(h, "obs_time");

    strcpy(pf->hdr.poln_type, "LIN");   // set based on known receivers
    if (get_hdr_int(h, "sum")) {
        strcpy(pf->hdr.poln_order, "AA+BB");
        pf->hdr.summed_polns = 1;
    } else if (w->numifs == 1) {
        strcpy(pf->hdr.poln_order, "AA");
        pf->hdr.summed_polns = 0;
    }
    strcpy(pf->hdr.track_mode, "TRACK");  // Potentially not-true?
    strcpy(pf->hdr.cal_mode, "OFF");      // Potentially not-true?
    strcpy(pf->hdr.feed_mode, "FA");      // check this...

    pf->hdr.beamnum = 0;
    if (get_hdr_int(h, "isalfa"))
        pf->hdr.beamnum = w->beamnum;

    pf->hdr.dt = w->dt;
    pf->hdr.fctr = w->fctr + 0.5 * (numwapps - 1.0) * w->BW;
    pf->hdr.BW = w->BW * numwapps;
    pf->hdr.beam_FWHM = beam_FWHM(pf->hdr.fctr, 300.0);
    pf->hdr.nchan = w->numchans * numwapps;
    pf->hdr.orig_nchan = w->numchans * numwapps;
    pf->hdr.orig_df = pf->hdr.df = pf->hdr.BW / pf->hdr.nchan;
    pf->hdr.nbits = numbits;
    pf->hdr.npol = w->numifs;
    pf->hdr.MJD_epoch = w->MJD_epoch;
    pf->hdr.start_day = (int) (w->MJD_epoch);
    pf->hdr.start_sec = (w->MJD_epoch - pf->hdr.start_day) * 86400.0;
    pf->hdr.scan_number = get_hdr_int(h, "scan_number");
    pf->hdr.ra2000 = w->ra;
    dec2hms(pf->hdr.ra_str, pf->hdr.ra2000 / 15.0, 0);
    pf->hdr.dec2000 = w->dec;
    dec2hms(pf->hdr.dec_str, pf->hdr.dec2000, 1);
    pf->hdr.azimuth = get_hdr_double(h, "start_az");
    pf->hdr.zenith_ang = get_hdr_double(h, "start_za");
    pf->hdr.rcvr_polns = 2;
    pf->hdr.offset_subint = 0;
    pf->hdr.onlyI = 0;
    pf->hdr.ds_time_fact = 1;
    pf->hdr.ds_freq_fact = 1;
    pf->hdr.chan_dm = 0.0;
    pf->hdr.fd_hand = pf->hdr.be_phase = 0;     // This is almost certainly not correct
    pf->hdr.fd_sang = pf->hdr.fd_xyph = 0.0;    // This is almost certainly not correct
    pf->hdr.feed_angle = 0.0;   // This is almost certainly not correct
    pf->hdr.cal_freq = pf->hdr.cal_dcyc = pf->hdr.cal_phs = 0.0;        //  ditto

    // Now set values for our subint structure
    pf->sub.tel_az = get_hdr_double(h, "start_az");
    pf->sub.tel_zen = get_hdr_double(h, "start_za");
    pf->sub.lst = get_hdr_double(h, "start_lst");
    pf->hdr.start_lst = pf->sub.lst;
    pf->sub.tsubint = pf->hdr.nsblk * pf->hdr.dt;
    pf->sub.ra = pf->hdr.ra2000;
    pf->sub.dec = pf->hdr.dec2000;
    pf->sub.offs = 0.5 * pf->sub.tsubint;
    slaEqgal(pf->hdr.ra2000 * DEGTORAD, pf->hdr.dec2000 * DEGTORAD,
             &pf->sub.glon, &pf->sub.glat);
    pf->sub.glon *= RADTODEG;
    pf->sub.glat *= RADTODEG;
    // The following three are unknown or hard to get, I think (SMR)
    pf->sub.feed_ang = 0.0;
    pf->sub.pos_ang = 0.0;
    pf->sub.par_ang = 0.0;
    pf->sub.bytes_per_subint = (pf->hdr.nbits * pf->hdr.nchan *
                                pf->hdr.npol * pf->hdr.nsblk) / 8;
    pf->sub.FITS_typecode = TBYTE;      // 11 = byte

    // Create and initialize the subint arrays
    pf->sub.dat_freqs = gen_fvect(pf->hdr.nchan);
    pf->sub.dat_weights = gen_fvect(pf->hdr.nchan);
    for (ii = 0; ii < pf->hdr.nchan; ii++) {
        pf->sub.dat_freqs[ii] = w->lofreq + ii * pf->hdr.df;
        pf->sub.dat_weights[ii] = 1.0;
    }

    // The following are re-set to try to preserve the band shape later
    pf->sub.dat_offsets = gen_fvect(pf->hdr.nchan * pf->hdr.npol);
    pf->sub.dat_scales = gen_fvect(pf->hdr.nchan * pf->hdr.npol);
    for (ii = 0; ii < pf->hdr.nchan * pf->hdr.npol; ii++) {
        pf->sub.dat_offsets[ii] = 0.0;
        pf->sub.dat_scales[ii] = 1.0;
    }

    // This is the raw data block that will be updated 
    // for each row of the PSRFITS file
    pf->sub.data = gen_bvect(pf->sub.bytes_per_subint);
}
Example #4
0
int prep_subbands(float *fdata, float *rawdata, int *delays, int numsubbands,
                  struct spectra_info *s, int transpose, 
                  int *maskchans, int *nummasked, mask * obsmask)
// This routine preps a block of raw spectra for subbanding.  It uses
// dispersion delays in 'delays' to de-disperse the data into
// 'numsubbands' subbands.  It stores the resulting data in vector
// 'fdata' of length 'numsubbands' * 's->spectra_per_subint'.  The low
// freq subband is stored first, then the next highest subband etc,
// with 's->spectra_per_subint' floating points per subband. It
// returns the # of points read if succesful, 0 otherwise.
// 'maskchans' is an array of length numchans which contains a list of
// the number of channels that were masked.  The # of channels masked
// is returned in 'nummasked'.  'obsmask' is the mask structure to use
// for masking.  If 'transpose'==0, the data will be kept in time
// order instead of arranged by subband as above.
{
   int ii, jj, trtn, offset;
   double starttime = 0.0;
   static float *tmpswap, *rawdata1, *rawdata2;
   static float *currentdata, *lastdata;
   static unsigned char *move;
   static int firsttime = 1, move_size = 0, mask = 0;

   *nummasked = 0;
   if (firsttime) {
       if (obsmask->numchan)
           mask = 1;
       move_size = (s->spectra_per_subint + numsubbands) / 2;
       move = gen_bvect(move_size);
       rawdata1 = gen_fvect(s->spectra_per_subint * s->num_channels);
       rawdata2 = gen_fvect(s->spectra_per_subint * s->num_channels);
       currentdata = rawdata1;
       lastdata = rawdata2;
   }

   /* Read and de-disperse */
   memcpy(currentdata, rawdata, s->spectra_per_subint * s->num_channels * sizeof(float));
   starttime = currentspectra * s->dt; // or -1 subint?
   if (mask)
      *nummasked = check_mask(starttime, s->time_per_subint, obsmask, maskchans);

   /* Clip nasty RFI if requested and we're not masking all the channels*/
   if ((s->clip_sigma > 0.0) && !(mask && (*nummasked == -1)))
      clip_times(currentdata, s->spectra_per_subint, s->num_channels, s->clip_sigma, s->padvals);

   if (mask) {
      if (*nummasked == -1) {   /* If all channels are masked */
         for (ii = 0; ii < s->spectra_per_subint; ii++)
             memcpy(currentdata + ii * s->num_channels, 
                    s->padvals, s->num_channels * sizeof(float));
      } else if (*nummasked > 0) {      /* Only some of the channels are masked */
         int channum;
         for (ii = 0; ii < s->spectra_per_subint; ii++) {
            offset = ii * s->num_channels;
            for (jj = 0; jj < *nummasked; jj++) {
               channum = maskchans[jj];
               currentdata[offset + channum] = s->padvals[channum];
            }
         }
      }
   }

   // In mpiprepsubband, the nodes do not call read_subbands() where
   // currentspectra gets incremented.
   if (using_MPI) currentspectra += s->spectra_per_subint;
   
   if (firsttime) {
       SWAP(currentdata, lastdata);
       firsttime = 0;
       return 0;
   } else {
       dedisp_subbands(currentdata, lastdata, s->spectra_per_subint, s->num_channels,
                       delays, numsubbands, fdata);
       SWAP(currentdata, lastdata);
       /* Transpose the data into vectors in the result array */
       if (transpose) {
           if ((trtn = transpose_float(fdata, s->spectra_per_subint, numsubbands,
                                       move, move_size)) < 0)
               printf("Error %d in transpose_float().\n", trtn);
       }
       return s->spectra_per_subint;
   }
}
void fill_psrfits_struct(int numbits, struct psrfits *pf, float dt, char* source, int nchantot, float df, int imjd, int smjd, float offs, char* ra, char* dec, float lofreq, char *basename)
{
    int ii;

    pf->filenum = 0;            // Crucial for initialization
    strcpy(pf->basefilename, basename);
    pf->hdr.nsblk = (int) (roundf(1.0 / dt));

    // Now set values for our hdrinfo structure
    strcpy(pf->hdr.telescope, "VLA");
    strcpy(pf->hdr.obs_mode, "SEARCH");
    strcpy(pf->hdr.backend, "YUPPI");
    strcpy(pf->hdr.frontend, "HFF");
    strcpy(pf->hdr.observer, " ");
    strcpy(pf->hdr.project_id, " ");
    strcpy(pf->hdr.source, source);
    strcpy(pf->hdr.date_obs, " ");
    //pf->hdr.scanlen = get_hdr_double(h, "obs_time");

    strcpy(pf->hdr.poln_type, "LIN");   // set based on known receivers
    strcpy(pf->hdr.poln_order, "AA");
    pf->hdr.summed_polns = 0;
    
    strcpy(pf->hdr.track_mode, "TRACK");  // Potentially not-true?
    strcpy(pf->hdr.cal_mode, "OFF");      // Potentially not-true?
    strcpy(pf->hdr.feed_mode, "FA");      // check this...

    pf->hdr.dt = dt;
    pf->hdr.fctr = lofreq + (nchantot/2.0 - 0.5)*df;
    pf->hdr.BW = nchantot*df;
    pf->hdr.beam_FWHM = beam_FWHM(pf->hdr.fctr, 34.0);
    pf->hdr.nchan = nchantot;
    pf->hdr.orig_nchan = nchantot;
    pf->hdr.df = df;
    pf->hdr.orig_df = df;
    pf->hdr.nbits = numbits;
    pf->hdr.npol = 1;
    pf->hdr.start_day = imjd;
    pf->hdr.start_sec = smjd;
    pf->hdr.MJD_epoch = (long double)imjd + ((long double)smjd + (long double)offs)/((long double)(24*3600));
    pf->hdr.scan_number = 0;
    strcpy(pf->hdr.ra_str, ra);
    strcpy(pf->hdr.dec_str, dec);
    
    pf->hdr.ra2000 = 0.0;
    pf->hdr.dec2000 = 0.0;

    pf->hdr.azimuth = 0.0;
    pf->hdr.zenith_ang = 0.0;
    pf->hdr.rcvr_polns = 1;
    pf->hdr.offset_subint = 0;
    pf->hdr.onlyI = 0;
    pf->hdr.ds_time_fact = 1;
    pf->hdr.ds_freq_fact = 1;
    pf->hdr.chan_dm = 0.0;
    pf->hdr.fd_hand = 1.0;
    pf->hdr.be_phase = 0;     // This is almost certainly not correct
    pf->hdr.fd_sang = pf->hdr.fd_xyph = 0.0;    // This is almost certainly not correct
    pf->hdr.feed_angle = 0.0;   // This is almost certainly not correct
    pf->hdr.cal_freq = pf->hdr.cal_dcyc = pf->hdr.cal_phs = 0.0;        //  ditto

    // Now set values for our subint structure
    pf->sub.tel_az = 0.0;
    pf->sub.tel_zen = 0.0;
    pf->sub.lst = 0.0;
    pf->sub.tsubint = pf->hdr.nsblk * pf->hdr.dt;
    pf->sub.ra = pf->hdr.ra2000;
    pf->sub.dec = pf->hdr.dec2000;
    pf->sub.offs = 0.5 * pf->sub.tsubint;
    //slaEqgal(pf->hdr.ra2000 * DEGTORAD, pf->hdr.dec2000 * DEGTORAD,
    //         &pf->sub.glon, &pf->sub.glat);
    //pf->sub.glon *= RADTODEG;
    //pf->sub.glat *= RADTODEG;
    // The following three are unknown or hard to get, I think (SMR)
    pf->sub.feed_ang = 0.0;
    pf->sub.pos_ang = 0.0;
    pf->sub.par_ang = 0.0;

    pf->sub.bytes_per_subint = (pf->hdr.nbits/8) * pf->hdr.nchan * pf->hdr.npol * pf->hdr.nsblk;

    pf->sub.FITS_typecode = TBYTE;        // newer, back to bytes
    //pf->sub.FITS_typecode = TFLOAT;     // new
    //pf->sub.FITS_typecode = TBYTE;      // 11 = byte

    // Create and initialize the subint arrays
    pf->sub.dat_freqs = gen_fvect(pf->hdr.nchan);
    pf->sub.dat_weights = gen_fvect(pf->hdr.nchan);
    for (ii = 0; ii < pf->hdr.nchan; ii++) {
        pf->sub.dat_freqs[ii] = lofreq + ii * pf->hdr.df;
        pf->sub.dat_weights[ii] = 1.0;
    }

    // The following are re-set to try to preserve the band shape later
    pf->sub.dat_offsets = gen_fvect(pf->hdr.nchan * pf->hdr.npol);
    pf->sub.dat_scales = gen_fvect(pf->hdr.nchan * pf->hdr.npol);
    for (ii = 0; ii < pf->hdr.nchan * pf->hdr.npol; ii++) {
        pf->sub.dat_offsets[ii] = 0.0;
        pf->sub.dat_scales[ii] = 1.0; 
    }

    // This is the raw data block that will be updated 
    // for each row of the PSRFITS file

    pf->sub.data = gen_bvect( pf->sub.bytes_per_subint );   // newest 
    //pf->sub.data = gen_bvect( (pf->sub.bytes_per_subint)/4 );   // newer
    //pf->sub.data = gen_fvect( (pf->sub.bytes_per_subint)/4 ); // new
    //pf->sub.data = gen_bvect(pf->sub.bytes_per_subint);
}
Example #6
0
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;
}