IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Changeset 34281


Ignore:
Timestamp:
Aug 2, 2012, 2:47:03 PM (14 years ago)
Author:
Serge CHASTEL
Message:

Rollback to version 34278

Location:
tags/ipp-20120802/ppTranslate
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • tags/ipp-20120802/ppTranslate

    • Property svn:mergeinfo deleted
  • tags/ipp-20120802/ppTranslate/src/ppMops.c

    r34280 r34281  
    6767    }
    6868
     69
    6970    psArray *detections = ppMopsRead(args); // Detections from each input
    7071    if (!detections) {
     
    9192    psLibFinalize();
    9293
    93 /*     fprintf (stderr, "found %d leaks at %s\n",  */
    94 /*      psMemCheckLeaks2 (0, */
    95 /*              NULL, stdout, false, 500), "ppMops"); */
     94    fprintf (stderr, "found %d leaks at %s\n",
     95        psMemCheckLeaks2 (0,
     96                NULL, stdout, false, 500), "ppMops");
    9697
    9798    return PS_EXIT_SUCCESS;
    9899}
    99100
     101
     102#if 0
     103    ps
     104
     105
     106    psArray *detections = NULL;         // Detections
     107    psMetadata *header = NULL;          // Header for detections
     108    {
     109        psFits *fits = psFitsOpen(data->detections, "r"); // FITS file
     110        header = psFitsReadHeader(NULL, fits);
     111        if (!header) {
     112            psErrorStackPrint(stderr, "Unable to read header");
     113            psFitsClose(fits);
     114            psFree(data);
     115            exit(PS_EXIT_DATA_ERROR);
     116        }
     117        if (!psFitsMoveExtName(fits, IN_EXTNAME)) {
     118            psErrorStackPrint(stderr, "Unable to move to extension %s", IN_EXTNAME);
     119            psFitsClose(fits);
     120            psFree(header);
     121            psFree(data);
     122            exit(PS_EXIT_DATA_ERROR);
     123        }
     124        detections = psFitsReadTable(fits);
     125        psFitsClose(fits);
     126        if (!detections) {
     127            psErrorStackPrint(stderr, "Unable to read detections");
     128            psFree(data);
     129            psFree(header);
     130            exit(PS_EXIT_DATA_ERROR);
     131        }
     132    }
     133
     134    // Translate the columns
     135    int numIn = detections->n;        // Number of rows in input
     136    int numOut = 0;                   // Number of rows in output
     137    psArray *output = psArrayAllocEmpty(numIn); // Output table
     138    double plateScale = 0.0;                 // Average plate scale
     139    for (int i = 0; i < numIn; i++) {
     140        psMetadata *inRow = detections->data[i]; // Input row
     141
     142        double ra = psMetadataLookupF64(NULL, inRow, "RA_PSF");
     143        double dec = psMetadataLookupF64(NULL, inRow, "DEC_PSF");
     144        double mag = psMetadataLookupF64(NULL, inRow, "PSF_INST_MAG") + data->zp;
     145        double magErr = psMetadataLookupF64(NULL, inRow, "PSF_INST_MAG_SIG");
     146        float ext = psMetadataLookupF32(NULL, inRow, "EXT_NSIGMA");
     147        double xErr = psMetadataLookupF64(NULL, inRow, "X_PSF_SIG");
     148        double yErr = psMetadataLookupF64(NULL, inRow, "Y_PSF_SIG");
     149        double scale = psMetadataLookupF64(NULL, inRow, "PLTSCALE");
     150        double angle = psMetadataLookupF64(NULL, inRow, "POSANGLE");
     151        psU32 flags = psMetadataLookupU32(NULL, inRow, "FLAGS");
     152
     153        if (!isfinite(mag) || !isfinite(magErr) || (flags & SOURCE_MASK) ||
     154            ((flags & PM_SOURCE_MODE_DEFECT) && !(flags & PM_SOURCE_MODE_MOMENTS_FAILURE))
     155            ) {
     156            // DEFECT can be due to bad moments
     157            continue;
     158        }
     159
     160        psMetadata *outRow = output->data[numOut] = psMetadataAlloc(); // Output row
     161
     162        numOut++;
     163        plateScale += scale;
     164
     165        // XXX Not at all sure I've got the angles around the right way here...
     166        double cosAngle = cos(angle), sinAngle = sin(angle);
     167        double cosAngle2 = PS_SQR(cosAngle), sinAngle2 = PS_SQR(sinAngle);
     168        double xErr2 = PS_SQR(xErr), yErr2 = PS_SQR(yErr);
     169        double errScale = scale / 3600.0;
     170        double raErr = errScale * sqrt(cosAngle2 * xErr2 + sinAngle2 * yErr2);
     171        double decErr = errScale * sqrt(sinAngle2 * xErr2 + cosAngle2 * yErr2);
     172
     173        psMetadataAddF64(outRow, PS_LIST_TAIL, "RA_DEG", 0, "Right ascension (degrees)", ra);
     174        psMetadataAddF64(outRow, PS_LIST_TAIL, "DEC_DEG", 0, "Declination (degrees)", dec);
     175        psMetadataAddF64(outRow, PS_LIST_TAIL, "RA_SIG", 0, "Right ascension error (degrees)", raErr);
     176        psMetadataAddF64(outRow, PS_LIST_TAIL, "DEC_SIG", 0, "Declination error (degrees)", decErr);
     177        psMetadataAddF64(outRow, PS_LIST_TAIL, "MAG", 0, "Magnitude", mag);
     178        psMetadataAddF64(outRow, PS_LIST_TAIL, "MAG_SIG", 0, "Magnitude error", magErr);
     179        psMetadataAddU32(outRow, PS_LIST_TAIL, "FLAGS", 0, "Detection bit flags", flags);
     180
     181        // The below need fixing
     182        psMetadataAddF64(outRow, PS_LIST_TAIL, "STARPSF", 0, "EXT_NSIGMA", ext);
     183        psMetadataAddF64(outRow, PS_LIST_TAIL, "ANG", 0, "Position angle of trail (degrees)", 0.0);
     184        psMetadataAddF64(outRow, PS_LIST_TAIL, "ANG_SIG", 0, "Position angle error (degrees)", 0.0);
     185        psMetadataAddF64(outRow, PS_LIST_TAIL, "LEN", 0, "Length of trail (arcsec)", 0.0);
     186        psMetadataAddF64(outRow, PS_LIST_TAIL, "LEN_SIG", 0, "Length error (arcsec)", 0.0);
     187    }
     188    output->n = numOut;
     189    plateScale /= numOut;
     190    psFree(detections);
     191
     192    // Translate the header
     193    psMetadata *outHeader = psMetadataAlloc(); // Output header
     194    ppMopsVersionHeader(outHeader);
     195    {
     196        const char *ra = psMetadataLookupStr(NULL, header, "FPA.RA");
     197        const char *dec = psMetadataLookupStr(NULL, header, "FPA.DEC");
     198        const char *filter = psMetadataLookupStr(NULL, header, "FPA.FILTER");
     199        float airmass = psMetadataLookupF32(NULL, header, "FPA.AIRMASS");
     200        float exptime = psMetadataLookupF32(NULL, header, "EXPTIME");
     201        double angle = psMetadataLookupF64(NULL, header, "FPA.POSANGLE");
     202        double alt = psMetadataLookupF64(NULL, header, "FPA.ALT");
     203        double az = psMetadataLookupF64(NULL, header, "FPA.AZ");
     204        psS64 imageid = psMetadataLookupS64(NULL, header, "IMAGEID");
     205        double mjd = psMetadataLookupF64(NULL, header, "MJD-OBS") + exptime / 2.0 / 3600 / 24;
     206
     207        float psf = plateScale * 0.5 * (psMetadataLookupF32(NULL, header, "FWHM_MAJ") +
     208                                        psMetadataLookupF32(NULL, header, "FWHM_MIN"));
     209
     210        psMetadataAddStr(outHeader, PS_LIST_TAIL, "RA", 0, "Right ascension of boresight", ra);
     211        psMetadataAddStr(outHeader, PS_LIST_TAIL, "DEC", 0, "Declination of boresight", dec);
     212        psMetadataAddF32(outHeader, PS_LIST_TAIL, "AIRMASS", 0, "Airmass of exposure", airmass);
     213        psMetadataAddF64(outHeader, PS_LIST_TAIL, "MJD-OBS", 0, "MJD of exposure midpoint", mjd);
     214        psMetadataAddStr(outHeader, PS_LIST_TAIL, "FILTER", 0, "Filter name", filter);
     215        psMetadataAddF64(outHeader, PS_LIST_TAIL, "EXPTIME", 0, "Exposure time (sec)", exptime);
     216        psMetadataAddF64(outHeader, PS_LIST_TAIL, "ROTANGLE", 0, "Rotator position angle", angle);
     217        psMetadataAddF64(outHeader, PS_LIST_TAIL, "TEL_ALT", 0, "Telescope altitude", alt);
     218        psMetadataAddF64(outHeader, PS_LIST_TAIL, "TEL_AZ", 0, "Telescope azimuth", az);
     219        psMetadataAddS64(outHeader, PS_LIST_TAIL, "DIFFIMID", 0, "Difference image identifier", imageid);
     220        psMetadataAddStr(outHeader, PS_LIST_TAIL, "FPA_ID", 0, "Exposure name", data->exp_name);
     221        psMetadataAddS64(outHeader, PS_LIST_TAIL, "EXP_ID", 0, "Exposure identifier", data->exp_id);
     222        psMetadataAddBool(outHeader, PS_LIST_TAIL, "POSITIVE", 0, "Positive subtraction?", data->direction);
     223        psMetadataAddStr(outHeader, PS_LIST_TAIL, "OBSCODE", 0, "IAU Observatory code", OBSERVATORY_CODE);
     224        psMetadataAddF32(outHeader, PS_LIST_TAIL, "STARPSF", 0, "Stellar PSF (arcsec)", psf);
     225
     226        // These are completely fake
     227        psMetadataAddF32(outHeader, PS_LIST_TAIL, "LIMITMAG", 0, "Limiting magnitude (FAKE)", 99.0);
     228        psMetadataAddF32(outHeader, PS_LIST_TAIL, "DE1", 0, "Detection efficiency (FAKE)", 0.0);
     229        psMetadataAddF32(outHeader, PS_LIST_TAIL, "DE2", 0, "Detection efficiency (FAKE)", 0.0);
     230        psMetadataAddF32(outHeader, PS_LIST_TAIL, "DE3", 0, "Detection efficiency (FAKE)", 0.0);
     231        psMetadataAddF32(outHeader, PS_LIST_TAIL, "DE4", 0, "Detection efficiency (FAKE)", 0.0);
     232        psMetadataAddF32(outHeader, PS_LIST_TAIL, "DE5", 0, "Detection efficiency (FAKE)", 0.0);
     233        psMetadataAddF32(outHeader, PS_LIST_TAIL, "DE6", 0, "Detection efficiency (FAKE)", 0.0);
     234        psMetadataAddF32(outHeader, PS_LIST_TAIL, "DE7", 0, "Detection efficiency (FAKE)", 0.0);
     235        psMetadataAddF32(outHeader, PS_LIST_TAIL, "DE8", 0, "Detection efficiency (FAKE)", 0.0);
     236        psMetadataAddF32(outHeader, PS_LIST_TAIL, "DE9", 0, "Detection efficiency (FAKE)", 0.0);
     237        psMetadataAddF32(outHeader, PS_LIST_TAIL, "DE10", 0, "Detection efficiency (FAKE)", 0.0);
     238    }
     239    psFree(header);
     240
     241    // Write the new table
     242    {
     243        psFits *fits = psFitsOpen(data->output, "w"); // FITS file
     244        if (!fits) {
     245            psErrorStackPrint(stderr, "Unable to open %s for writing", data->output);
     246            psFree(outHeader);
     247            psFree(output);
     248            psFree(data);
     249            exit(PS_EXIT_SYS_ERROR);
     250        }
     251
     252        if (numOut == 0) {
     253            // Write dummy table
     254            psMetadata *outRow = psMetadataAlloc(); // Dummy output row
     255            psMetadataAddF64(outRow, PS_LIST_TAIL, "RA_DEG", 0, "Right ascension (degrees)", NAN);
     256            psMetadataAddF64(outRow, PS_LIST_TAIL, "DEC_DEG", 0, "Declination (degrees)", NAN);
     257            psMetadataAddF64(outRow, PS_LIST_TAIL, "RA_SIG", 0, "Right ascension error (degrees)", NAN);
     258            psMetadataAddF64(outRow, PS_LIST_TAIL, "DEC_SIG", 0, "Declination error (degrees)", NAN);
     259            psMetadataAddF64(outRow, PS_LIST_TAIL, "MAG", 0, "Magnitude", NAN);
     260            psMetadataAddF64(outRow, PS_LIST_TAIL, "MAG_SIG", 0, "Magnitude error", NAN);
     261            psMetadataAddU32(outRow, PS_LIST_TAIL, "FLAGS", 0, "Detection bit flags", 0);
     262
     263            // The below need fixing
     264            psMetadataAddF64(outRow, PS_LIST_TAIL, "STARPSF", 0, "EXT_NSIGMA", NAN);
     265            psMetadataAddF64(outRow, PS_LIST_TAIL, "ANG", 0, "Position angle of trail (degrees)", NAN);
     266            psMetadataAddF64(outRow, PS_LIST_TAIL, "ANG_SIG", 0, "Position angle error (degrees)", NAN);
     267            psMetadataAddF64(outRow, PS_LIST_TAIL, "LEN", 0, "Length of trail (arcsec)", NAN);
     268            psMetadataAddF64(outRow, PS_LIST_TAIL, "LEN_SIG", 0, "Length error (arcsec)", NAN);
     269            if (!psFitsWriteTableEmpty(fits, outHeader, outRow, OUT_EXTNAME)) {
     270                psErrorStackPrint(stderr, "Unable to write table.");
     271                psFree(outHeader);
     272                psFree(output);
     273                psFree(outRow);
     274                psFree(data);
     275                exit(PS_EXIT_SYS_ERROR);
     276            }
     277            psFree(outRow);
     278        } else if (!psFitsWriteTable(fits, outHeader, output, OUT_EXTNAME)) {
     279            psErrorStackPrint(stderr, "Unable to write table.");
     280            psFree(outHeader);
     281            psFree(output);
     282            psFree(data);
     283            exit(PS_EXIT_SYS_ERROR);
     284        }
     285        psFitsClose(fits);
     286    }
     287
     288    psFree(outHeader);
     289    psFree(output);
     290    psFree(data);
     291
     292#endif
     293
  • tags/ipp-20120802/ppTranslate/src/ppMops.h

    r34280 r34281  
    3030} ppMopsArguments;
    3131
     32#if 0
     33#warning "IS THERE ANYTHING TO BE MODIFIED HERE?"
     34TTYPE19 = 'PSF_CHISQ'          / label for field  19
     35TFORM19 = '1E      '           / data format of field: 4-byte REAL
     36TTYPE20 = 'CR_NSIGMA'          / label for field  20
     37TFORM20 = '1E      '           / data format of field: 4-byte REAL
     38TTYPE21 = 'EXT_NSIGMA'         / label for field  21
     39TFORM21 = '1E      '           / data format of field: 4-byte REAL
     40TTYPE22 = 'PSF_MAJOR'          / label for field  22
     41TFORM22 = '1E      '           / data format of field: 4-byte REAL
     42TTYPE23 = 'PSF_MINOR'          / label for field  23
     43TFORM23 = '1E      '           / data format of field: 4-byte REAL
     44TTYPE24 = 'PSF_THETA'          / label for field  24
     45TFORM24 = '1E      '           / data format of field: 4-byte REAL
     46TTYPE25 = 'PSF_QF  '           / label for field  25
     47TFORM25 = '1E      '           / data format of field: 4-byte REAL
     48TTYPE26 = 'PSF_NDOF'           / label for field  26
     49TFORM26 = '1J      '           / data format of field: 4-byte INTEGER
     50TTYPE27 = 'PSF_NPIX'           / label for field  27
     51TFORM27 = '1J      '           / data format of field: 4-byte INTEGER
     52TTYPE28 = 'MOMENTS_XX'         / label for field  28
     53TFORM28 = '1E      '           / data format of field: 4-byte REAL
     54TTYPE29 = 'MOMENTS_XY'         / label for field  29
     55TFORM29 = '1E      '           / data format of field: 4-byte REAL
     56TTYPE30 = 'MOMENTS_YY'         / label for field  30
     57TFORM30 = '1E      '           / data format of field: 4-byte REAL
     58#endif
     59
    3260/// Parse arguments
    3361ppMopsArguments *ppMopsArgumentsParse(int argc, char *argv[]);
     
    4775  long numGood;                       // Number of "good" detections
    4876  psS64 diffSkyfileId;                // unique id for input skyfile
    49   psMetadata *table;                  // Columns from the input file (SkyChip.psf extension)
    50   psMetadata *fittedTrails;           // Columns from the fitted trails (SkyChip.xfit extension)
    51   long fittedTrailsSize;       // Size of the fitted trails (SkyChip.xfit extension)
     77  psMetadata *table;                  // Columns from the input file
    5278  psVector *x, *y;                    // Image coordinates
    5379  psVector *ra, *dec;                 // Sky coordinates
     
    77103/// @returns 1 if EXTTYPE of "SkyChip.psf" is PS1_DV1
    78104/// @returns 2 if EXTTYPE of "SkyChip.psf" is PS1_DV2
    79 /// @returns 3 if EXTTYPE of "SkyChip.psf" is PS1_DV3
    80105/// @returns 0 otherwise
    81106int ppMopsGetSkyChipPsfVersion(const psFits* fits);
  • tags/ipp-20120802/ppTranslate/src/ppMopsArguments.c

    r34280 r34281  
    3434    fprintf(stderr, "\n");
    3535    psArgumentHelp(arguments);
    36     fprintf(stderr, "\t\tCMF file version can be set to either 1 for PS1_DV1, 2 for PS1_DV2, or 3 for PS1_DV3\n");
     36    fprintf(stderr, "\t\tCMF file version can be set to either 1 for PS1_DV1 or 2 for PS1_DV1\n");
    3737    fprintf(stderr, "\t\tSee IPP-MOPS ICD for details\n");
    3838    psLibFinalize();
  • tags/ipp-20120802/ppTranslate/src/ppMopsGetSkyChipPsfVersion.c

    r34280 r34281  
    1414    psFree(headerSkyChip);
    1515    return 2;
    16   } else if (strcmp(version, "PS1_DV3") == 0) {
    17     psFree(headerSkyChip);
    18     return 2;
    1916  }
    2017  psWarning("Unsupported EXTTYPE in SkyChip.psf table: [%s]", version);
  • tags/ipp-20120802/ppTranslate/src/ppMopsMerge.c

    r34280 r34281  
    7171
    7272    for (int i = 0; i < numInputs; i++) {
    73       psTrace("ppMops.merge", 1, "Processing batch %d\n", i);
    7473        ppMopsDetections *det = detections->data[i]; // Detections of interest
    7574        if (!det) {
  • tags/ipp-20120802/ppTranslate/src/ppMopsRead.c

    r34280 r34281  
    88#include "ppMops.h"
    99
    10 static psMetadata* sort_by_increasing_idet(psMetadata *fittedTrail, long length, long fillLength);
    11 
    1210/*
    1311  ppMopsRead possibly modifies the args->version if the user did not
    1412  set it explicitely.
    15 */
     13 */
    1614psArray *ppMopsRead(ppMopsArguments *args)
    1715{
    18   psTrace("ppMops.read", 1, "Reading input detections\n");
    19 
    20   psArray *inNames = args->input;          // Input names
    21   long num = inNames->n;                   // Number of inputs
    22   psArray *detections = psArrayAlloc(num); // Array of detections, to return
    23   for (int i = 0; i < num; i++) {
    24     const char *name = inNames->data[i];
    25 
    26     psFits *fits = psFitsOpen(name,  "r"); // FITS file
    27     if (!fits) {
    28       psError(PS_ERR_IO, false, "Unable to open input %d", i);
    29       return false;
     16    psTrace("ppMops.read", 1, "Reading input detections\n");
     17
     18    psArray *inNames = args->input;          // Input names
     19    long num = inNames->n;                   // Number of inputs
     20    psArray *detections = psArrayAlloc(num); // Array of detections, to return
     21    for (int i = 0; i < num; i++) {
     22        const char *name = inNames->data[i];
     23
     24        psFits *fits = psFitsOpen(name,  "r"); // FITS file
     25        if (!fits) {
     26            psError(PS_ERR_IO, false, "Unable to open input %d", i);
     27            return false;
     28        }
     29
     30        psMetadata *header = psFitsReadHeader(NULL, fits); // Primary header
     31        if (!header) {
     32            psError(PS_ERR_IO, false, "Unable to read header %d", i);
     33            return false;
     34        }
     35
     36        psS64 diffSkyfileId = psMetadataLookupS64(NULL, header, "IMAGEID"); // Identifier for image
     37        if (diffSkyfileId == 0) {
     38            psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find identifier for image %d", i);
     39            return false;
     40        }
     41
     42        if (!psFitsMoveExtName(fits, "SkyChip.psf")) {
     43            psError(PS_ERR_IO, false, "Unable to move to HDU with detections");
     44            return false;
     45        }
     46        int skyChipPsfVersion = ppMopsGetSkyChipPsfVersion(fits);
     47        if (args->version == 0) {
     48          psTrace("ppMops.read", 1, "Changing args->version to %d\n", skyChipPsfVersion);
     49          args->version = (unsigned short) skyChipPsfVersion;
     50        }
     51        if (skyChipPsfVersion == 0) {
     52          // Try to read with the user specified version?
     53          skyChipPsfVersion = args->version;
     54        }
     55        /* Display a warning message if there are version
     56           inconsistencies between the file and the flag (note that
     57           those inconsistencies might be wanted) */
     58        if (skyChipPsfVersion != args->version) {
     59          if (skyChipPsfVersion > args->version) {
     60            psWarning("The FITS data will be downgraded from PS1_DV%d to PS1_DV%d\n",
     61                      skyChipPsfVersion, args->version);
     62          } else { // Necessarily: skyChipPsfVersion > args->version
     63            psWarning("The FITS data will be upgraded from PS1_DV%d to PS1_DV%d (new values set to default 0, NaN...)\n",
     64                      skyChipPsfVersion, args->version);           
     65          }
     66        }
     67
     68        long size = psFitsTableSize(fits); // Size of table
     69        if (size <= 0) {
     70            psErrorStackPrint(stderr, "Unable to determine size of table %d", i);
     71            psErrorClear();
     72            psWarning("Ignoring input %d", i);
     73            psFree(header);
     74            psFitsClose(fits);
     75            continue;
     76        }
     77        ppMopsDetections *det = ppMopsDetectionsAlloc(size);
     78        detections->data[i] = det;
     79        det->component = psStringNCopy(name, strrchr(name, '.') - name); // Strip off extension
     80        det->num = size;
     81        det->diffSkyfileId = diffSkyfileId;
     82
     83        psTrace("ppMops.read", 3, "Reading %ld rows from %s\n", size, (const char*)inNames->data[i]);
     84
     85        det->raBoresight = psMemIncrRefCounter(psMetadataLookupStr(NULL, header, "FPA.RA"));
     86        det->decBoresight = psMemIncrRefCounter(psMetadataLookupStr(NULL, header, "FPA.DEC"));
     87        det->filter = psMemIncrRefCounter(psMetadataLookupStr(NULL, header, "FPA.FILTER"));
     88        det->airmass = psMetadataLookupF32(NULL, header, "AIRMASS");
     89        det->exptime = psMetadataLookupF32(NULL, header, "EXPTIME");
     90        det->posangle = psMetadataLookupF64(NULL, header, "FPA.POSANGLE");
     91        det->alt = psMetadataLookupF64(NULL, header, "FPA.ALT");
     92        det->az = psMetadataLookupF64(NULL, header, "FPA.AZ");
     93        det->mjd = psMetadataLookupF64(NULL, header, "MJD-OBS") + det->exptime / 2.0 / 3600 / 24;
     94
     95        det->seeing = (float) 0.5 * (psMetadataLookupF32(NULL, header, "FWHM_MAJ") +
     96                                     psMetadataLookupF32(NULL, header, "FWHM_MIN"));
     97
     98        det->naxis1 = psMetadataLookupS32(NULL, header, "IMNAXIS1"); // Number of columns
     99        det->naxis2 = psMetadataLookupS32(NULL, header, "IMNAXIS2"); // Number of rows
     100
     101        psFree(header);
     102
     103        psMetadata *table = psFitsReadTableAllColumns(fits); // Table of interest
     104        if (!table) {
     105            psError(PS_ERR_IO, false, "Unable to read table %d", i);
     106            return NULL;
     107        }
     108        det->table = table;
     109        psFitsClose(fits);
     110        if (args->version == 0) {
     111          if (skyChipPsfVersion < 2) {
     112            // XXX: TODO: Do we need to add dummy vectors for the missing columns?
     113           }
     114        }
     115
     116        psVector *ra = psMetadataLookupVector(NULL, table, "RA_PSF");
     117        psVector *dec = psMetadataLookupVector(NULL, table, "DEC_PSF");
     118
     119        det->raErr = psVectorAlloc(size, PS_TYPE_F64);
     120        det->decErr = psVectorAlloc(size, PS_TYPE_F64);
     121        det->mask = psVectorAlloc(size, PS_TYPE_U8);
     122
     123        // convert ra and dec to radians for use in the purge duplicates function
     124        det->ra = (psVector*)psBinaryOp(NULL, ra, "*", psScalarAlloc(DEG_TO_RAD(1.0), PS_TYPE_F64));
     125        det->dec = (psVector*)psBinaryOp(NULL, dec, "*", psScalarAlloc(DEG_TO_RAD(1.0), PS_TYPE_F64));
     126        det->x = psMemIncrRefCounter(psMetadataLookupVector(NULL, table, "X_PSF"));
     127        det->y = psMemIncrRefCounter(psMetadataLookupVector(NULL, table, "Y_PSF"));
     128        if (!det->ra || !det->dec || !det->x || !det->y) {
     129            psError(PS_ERR_UNEXPECTED_NULL, true, "Unable to find all of RA, Dec, X and Y columns");
     130            return NULL;
     131        }
     132
     133        // Add our new vectors to the table so that duplicates and masked items may be purged
     134        psMetadataAddVector(table, PS_LIST_HEAD, "DEC_ERR", 0, NULL, det->decErr);
     135        psMetadataAddVector(table, PS_LIST_HEAD, "RA_ERR", 0, NULL, det->raErr);
     136
     137        psTrace("ppMops.read", 2, "Read %ld rows from %s\n", det->num, det->component);
     138
     139        psVector *mag    = psMetadataLookupVector(NULL, table, "PSF_INST_MAG");
     140        psVector *magErr = psMetadataLookupVector(NULL, table, "PSF_INST_MAG_SIG");
     141        psVector *xErrV  = psMetadataLookupVector(NULL, table, "X_PSF_SIG");
     142        psVector *yErrV  = psMetadataLookupVector(NULL, table, "Y_PSF_SIG");
     143        psVector *scaleV = psMetadataLookupVector(NULL, table, "PLTSCALE");
     144        psVector *angleV = psMetadataLookupVector(NULL, table, "POSANGLE");
     145        psVector *flagsV = psMetadataLookupVector(NULL, table, "FLAGS");
     146
     147        double plateScale = 0.0;        // Plate scale
     148        long numGood = 0;               // Number of good rows
     149        for (long row = 0; row < size; row++) {
     150
     151            psU32 flags = flagsV->data.U32[row]; // psFitsTableGetU32(NULL, table, row, "FLAGS");
     152            if (flags & SOURCE_MASK) {
     153                psTrace("ppMops.read", 10, "Discarding row %ld from input %d because of flags: %ud", row, i, flags);
     154                det->mask->data.U8[row] = 0xFF;
     155                continue;
     156            }
     157
     158            // Calculate error in RA, Dec
     159
     160            double xErr = xErrV->data.F32[row];
     161            double yErr = yErrV->data.F32[row];
     162            double scale = scaleV->data.F32[row];
     163            double angle = angleV->data.F32[row];
     164
     165            if (!isfinite(det->x->data.F32[row]) || !isfinite(det->y->data.F32[row]) ||
     166                !isfinite(det->ra->data.F64[row]) || !isfinite(det->dec->data.F64[row]) ||
     167                !isfinite(mag->data.F32[row]) || !isfinite(magErr->data.F32[row]) ||
     168                !isfinite(xErr) || !isfinite(yErr) || !isfinite(scale) || !isfinite(angle)) {
     169                psTrace("ppMops.read", 10,
     170                        "Discarding row %ld from input %d because of non-finite values: "
     171                        "%f %f %lf %lf %f %f %f %f %f %f",
     172                        row, i,
     173                        det->x->data.F32[row], det->y->data.F32[row],
     174                        det->ra->data.F64[row], det->dec->data.F64[row],
     175                        mag->data.F32[row], magErr->data.F32[row],
     176                        xErr, yErr, scale, angle);
     177                det->mask->data.U8[row] = 0xFF;
     178                continue;
     179            }
     180
     181            // XXX Not at all sure I've got the angles around the right way here...
     182            double cosAngle = cos(angle), sinAngle = sin(angle);
     183            double cosAngle2 = PS_SQR(cosAngle), sinAngle2 = PS_SQR(sinAngle);
     184            double xErr2 = PS_SQR(xErr), yErr2 = PS_SQR(yErr);
     185            double errScale = scale / 3600.0;
     186            det->raErr->data.F64[row] = errScale * sqrt(cosAngle2 * xErr2 + sinAngle2 * yErr2);
     187            det->decErr->data.F64[row] = errScale * sqrt(sinAngle2 * xErr2 + cosAngle2 * yErr2);
     188
     189            det->mask->data.U8[row] = 0;
     190            plateScale += scale;
     191            numGood++;
     192        }
     193        det->seeing *= ((float) plateScale) / ((float) numGood);
     194
     195        // Are we using numGood for anything outside of this function?
     196        det->numGood = numGood;
     197
     198        if (isfinite(args->zp) && numGood > 0) {
     199            psBinaryOp(mag, mag, "+", psScalarAlloc(args->zp, PS_TYPE_F32));
     200        }
     201
     202        psTrace("ppMops.read", 2, "Read %ld good rows from %s\n", numGood, (const char*)name);
    30203    }
    31204
    32     psMetadata *header = psFitsReadHeader(NULL, fits); // Primary header
    33     if (!header) {
    34       psError(PS_ERR_IO, false, "Unable to read header %d", i);
    35       return false;
    36     }
    37 
    38     psS64 diffSkyfileId = psMetadataLookupS64(NULL, header, "IMAGEID"); // Identifier for image
    39     if (diffSkyfileId == 0) {
    40       psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find identifier for image %d", i);
    41       return false;
    42     }
    43 
    44     if (!psFitsMoveExtName(fits, "SkyChip.psf")) {
    45       psError(PS_ERR_IO, false, "Unable to move to HDU with detections");
    46       return false;
    47     }
    48     int skyChipPsfVersion = ppMopsGetSkyChipPsfVersion(fits);
    49     if (args->version == 0) {
    50       psTrace("ppMops.read", 1, "Changing args->version to %d\n", skyChipPsfVersion);
    51       args->version = (unsigned short) skyChipPsfVersion;
    52     }
    53     if (skyChipPsfVersion == 0) {
    54       // Try to read with the user specified version?
    55       skyChipPsfVersion = args->version;
    56     }
    57     /* Display a warning message if there are version
    58        inconsistencies between the file and the flag (note that
    59        those inconsistencies might be wanted) */
    60     if (skyChipPsfVersion != args->version) {
    61       if (skyChipPsfVersion > args->version) {
    62         psWarning("The FITS data will be downgraded from PS1_DV%d to PS1_DV%d\n",
    63                   skyChipPsfVersion, args->version);
    64       } else { // Necessarily: skyChipPsfVersion > args->version
    65         psWarning("The FITS data will be upgraded from PS1_DV%d to PS1_DV%d (new values set to default 0, NaN...)\n",
    66                   skyChipPsfVersion, args->version);
    67       }
    68     }
    69 
    70     long size = psFitsTableSize(fits); // Size of table
    71     if (size <= 0) {
    72       psErrorStackPrint(stderr, "Unable to determine size of table %d", i);
    73       psErrorClear();
    74       psWarning("Ignoring input %d", i);
    75       psFree(header);
    76       psFitsClose(fits);
    77       continue;
    78     }
    79     ppMopsDetections *det = ppMopsDetectionsAlloc(size);
    80     detections->data[i] = det;
    81     det->component = psStringNCopy(name, strrchr(name, '.') - name); // Strip off extension
    82     det->num = size;
    83     det->diffSkyfileId = diffSkyfileId;
    84 
    85     psTrace("ppMops.read", 3, "Reading %ld rows from %s\n", size, (const char*)inNames->data[i]);
    86 
    87     det->raBoresight = psMemIncrRefCounter(psMetadataLookupStr(NULL, header, "FPA.RA"));
    88     det->decBoresight = psMemIncrRefCounter(psMetadataLookupStr(NULL, header, "FPA.DEC"));
    89     det->filter = psMemIncrRefCounter(psMetadataLookupStr(NULL, header, "FPA.FILTER"));
    90     det->airmass = psMetadataLookupF32(NULL, header, "AIRMASS");
    91     det->exptime = psMetadataLookupF32(NULL, header, "EXPTIME");
    92     det->posangle = psMetadataLookupF64(NULL, header, "FPA.POSANGLE");
    93     det->alt = psMetadataLookupF64(NULL, header, "FPA.ALT");
    94     det->az = psMetadataLookupF64(NULL, header, "FPA.AZ");
    95     det->mjd = psMetadataLookupF64(NULL, header, "MJD-OBS") + det->exptime / 2.0 / 3600 / 24;
    96 
    97     det->seeing = (float) 0.5 * (psMetadataLookupF32(NULL, header, "FWHM_MAJ") +
    98                                  psMetadataLookupF32(NULL, header, "FWHM_MIN"));
    99 
    100     det->naxis1 = psMetadataLookupS32(NULL, header, "IMNAXIS1"); // Number of columns
    101     det->naxis2 = psMetadataLookupS32(NULL, header, "IMNAXIS2"); // Number of rows
    102 
    103     psFree(header);
    104 
    105     psMetadata *table = psFitsReadTableAllColumns(fits); // Table of interest
    106     if (!table) {
    107       psError(PS_ERR_IO, false, "Unable to read table %d", i);
    108       return NULL;
    109     }
    110     //Sort table by idet if necessary
    111     psMetadata* sortedTable = sort_by_increasing_idet(table, det->num, det->num);
    112     if (sortedTable != table) {
    113       psFree(table);
    114       table = sortedTable;
    115     } // else det->table is sorted
    116     det->table = table;
    117     psTrace("ppMops.read", 9, "PSF table:\n%s\n", psMetadataConfigFormat(det->table));
    118     psTrace("ppMops.read", 9, "End of PSF table\n");
    119 
    120     //fittedTrail extension (Supported for releases 2 and above)
    121     if (skyChipPsfVersion >= 2) {
    122       if (!psFitsMoveExtName(fits, "SkyChip.xfit")) {
    123         psTrace("ppMops.read", 3, "No fitted trails extension");
    124       } else {
    125         psTrace("ppMops.read", 3, "Fitted trails extension found\n");
    126         det->fittedTrailsSize = psFitsTableSize(fits);
    127         if (det->fittedTrailsSize <= 0) {
    128           psErrorStackPrint(stderr, "Unable to determine size of fitted trails extension table %d", i);
    129           psTrace("ppMops.read", 3, "No entry in fitted trails extension!!!!\n");
    130           psErrorClear();
    131           det->fittedTrails = NULL;
    132         } else {
    133           det->fittedTrails = psFitsReadTableAllColumns(fits); // Table of interest
    134           if (!det->fittedTrails) {
    135             psError(PS_ERR_IO, false, "Unable to read fittedTrails table %d", i);
    136             return NULL;
    137           }
    138           psMetadata* sortedFittedTrails = sort_by_increasing_idet(det->fittedTrails, det->fittedTrailsSize, det->num);
    139           if (sortedFittedTrails != det->fittedTrails) {
    140             psFree(det->fittedTrails);
    141             det->fittedTrails = sortedFittedTrails;
    142           } // else det->fittedTrails is sorted
    143           psTrace("ppMops.read", 9, "Fitted trail:\n%s\n", psMetadataConfigFormat(det->fittedTrails));
    144           psTrace("ppMops.read", 9, "End of Fitted trail\n");
    145         }
    146       }
    147     }
    148 
    149     psFitsClose(fits);
    150 
    151     if (args->version == 0) {
    152       if (skyChipPsfVersion < 2) {
    153         // XXX: TODO: Do we need to add dummy vectors for the missing columns?
    154       }
    155     }
    156 
    157     psVector *ra = psMetadataLookupVector(NULL, table, "RA_PSF");
    158     psVector *dec = psMetadataLookupVector(NULL, table, "DEC_PSF");
    159 
    160     det->raErr = psVectorAlloc(size, PS_TYPE_F64);
    161     det->decErr = psVectorAlloc(size, PS_TYPE_F64);
    162     det->mask = psVectorAlloc(size, PS_TYPE_U8);
    163 
    164     // convert ra and dec to radians for use in the purge duplicates function
    165     det->ra = (psVector*)psBinaryOp(NULL, ra, "*", psScalarAlloc(DEG_TO_RAD(1.0), PS_TYPE_F64));
    166     det->dec = (psVector*)psBinaryOp(NULL, dec, "*", psScalarAlloc(DEG_TO_RAD(1.0), PS_TYPE_F64));
    167     det->x = psMemIncrRefCounter(psMetadataLookupVector(NULL, table, "X_PSF"));
    168     det->y = psMemIncrRefCounter(psMetadataLookupVector(NULL, table, "Y_PSF"));
    169     if (!det->ra || !det->dec || !det->x || !det->y) {
    170       psError(PS_ERR_UNEXPECTED_NULL, true, "Unable to find all of RA, Dec, X and Y columns");
    171       return NULL;
    172     }
    173 
    174     // Add our new vectors to the table so that duplicates and masked items may be purged
    175     psMetadataAddVector(table, PS_LIST_HEAD, "DEC_ERR", 0, NULL, det->decErr);
    176     psMetadataAddVector(table, PS_LIST_HEAD, "RA_ERR", 0, NULL, det->raErr);
    177 
    178     psTrace("ppMops.read", 2, "Read %ld rows from %s\n", det->num, det->component);
    179 
    180     psVector *mag    = psMetadataLookupVector(NULL, table, "PSF_INST_MAG");
    181     psVector *magErr = psMetadataLookupVector(NULL, table, "PSF_INST_MAG_SIG");
    182     psVector *xErrV  = psMetadataLookupVector(NULL, table, "X_PSF_SIG");
    183     psVector *yErrV  = psMetadataLookupVector(NULL, table, "Y_PSF_SIG");
    184     psVector *scaleV = psMetadataLookupVector(NULL, table, "PLTSCALE");
    185     psVector *angleV = psMetadataLookupVector(NULL, table, "POSANGLE");
    186     psVector *flagsV = psMetadataLookupVector(NULL, table, "FLAGS");
    187 
    188     double plateScale = 0.0;        // Plate scale
    189     long numGood = 0;               // Number of good rows
    190     for (long row = 0; row < size; row++) {
    191 
    192       psU32 flags = flagsV->data.U32[row]; // psFitsTableGetU32(NULL, table, row, "FLAGS");
    193       if (flags & SOURCE_MASK) {
    194         psTrace("ppMops.read", 10, "Discarding row %ld from input %d because of flags: %ud", row, i, flags);
    195         det->mask->data.U8[row] = 0xFF;
    196         continue;
    197       }
    198 
    199       // Calculate error in RA, Dec
    200 
    201       double xErr = xErrV->data.F32[row];
    202       double yErr = yErrV->data.F32[row];
    203       double scale = scaleV->data.F32[row];
    204       double angle = angleV->data.F32[row];
    205 
    206       if (!isfinite(det->x->data.F32[row]) || !isfinite(det->y->data.F32[row]) ||
    207           !isfinite(det->ra->data.F64[row]) || !isfinite(det->dec->data.F64[row]) ||
    208           !isfinite(mag->data.F32[row]) || !isfinite(magErr->data.F32[row]) ||
    209           !isfinite(xErr) || !isfinite(yErr) || !isfinite(scale) || !isfinite(angle)) {
    210         psTrace("ppMops.read", 10,
    211                 "Discarding row %ld from input %d because of non-finite values: "
    212                 "%f %f %lf %lf %f %f %f %f %f %f",
    213                 row, i,
    214                 det->x->data.F32[row], det->y->data.F32[row],
    215                 det->ra->data.F64[row], det->dec->data.F64[row],
    216                 mag->data.F32[row], magErr->data.F32[row],
    217                 xErr, yErr, scale, angle);
    218         det->mask->data.U8[row] = 0xFF;
    219         continue;
    220       }
    221 
    222       // XXX Not at all sure I've got the angles around the right way here...
    223       double cosAngle = cos(angle), sinAngle = sin(angle);
    224       double cosAngle2 = PS_SQR(cosAngle), sinAngle2 = PS_SQR(sinAngle);
    225       double xErr2 = PS_SQR(xErr), yErr2 = PS_SQR(yErr);
    226       double errScale = scale / 3600.0;
    227       det->raErr->data.F64[row] = errScale * sqrt(cosAngle2 * xErr2 + sinAngle2 * yErr2);
    228       det->decErr->data.F64[row] = errScale * sqrt(sinAngle2 * xErr2 + cosAngle2 * yErr2);
    229       det->mask->data.U8[row] = 0;
    230       plateScale += scale;
    231       numGood++;
    232     }
    233     det->seeing *= ((float) plateScale) / ((float) numGood);
    234 
    235     // Are we using numGood for anything outside of this function?
    236     det->numGood = numGood;
    237 
    238     if (isfinite(args->zp) && numGood > 0) {
    239       psBinaryOp(mag, mag, "+", psScalarAlloc(args->zp, PS_TYPE_F32));
    240     }
    241 
    242     psTrace("ppMops.read", 2, "Read %ld good rows from %s\n", numGood, (const char*)name);
    243   }
    244 
    245   psTrace("ppMops.read", 1, "Done reading input detections\n");
    246 
    247   return detections;
     205    psTrace("ppMops.read", 1, "Done reading input detections\n");
     206
     207    return detections;
    248208}
    249 
    250 static long* sorted_idets_indexes(psVector *idets);
    251 static int compare (const void *a, const void *b);
    252 static psVector* fill_F32_vector(psVector* in, int size, long* indexes, int indexes_length);
    253 
    254 // We want the entries in table/fittedTrails to be sorted by increasing idet
    255 static psMetadata* sort_by_increasing_idet(psMetadata *aTable, long length, long fillLength) {
    256   if (aTable == NULL) {
    257     return aTable;
    258   }
    259   psVector *idets = psMetadataLookupVector(NULL, aTable, "IPP_IDET");
    260   if (!idets) {
    261     psError(PS_ERR_PROGRAMMING, true, "Failed to find IPP_IDET column");
    262     return NULL;
    263   }
    264   bool is_sorted = true;
    265   int count = 0;
    266   long previous_value = -1;
    267   while (is_sorted && (count<length) ){
    268     is_sorted = (previous_value < idets->data.S64[count]);
    269     previous_value = idets->data.S64[count];
    270     count += 1;
    271   }
    272   if (is_sorted && (length==fillLength)) {
    273     psTrace("ppMops.read", 5, "Values are already sorted by idet and the table is complete\n");
    274     return aTable;
    275   }
    276   //otherwise sort (even if it should not happen) and fill
    277   long* sortedIndexVector = sorted_idets_indexes(idets);
    278   psMetadata* sortedTable = psMetadataAlloc();
    279   char* column_name = "X_EXT";
    280   psMetadataAddVector( sortedTable, PS_LIST_TAIL, column_name, 0, NULL,
    281                        fill_F32_vector(psMetadataLookupVector(NULL, aTable, column_name), fillLength, sortedIndexVector, idets->n) );
    282   column_name = "Y_EXT";
    283   psMetadataAddVector( sortedTable, PS_LIST_TAIL, column_name, 0, NULL,
    284                        fill_F32_vector(psMetadataLookupVector(NULL, aTable, column_name), fillLength, sortedIndexVector, idets->n) );
    285   column_name = "X_EXT_SIG";
    286   psMetadataAddVector( sortedTable, PS_LIST_TAIL, column_name, 0, NULL,
    287                        fill_F32_vector(psMetadataLookupVector(NULL, aTable, column_name), fillLength, sortedIndexVector, idets->n) );
    288   column_name = "Y_EXT_SIG";
    289   psMetadataAddVector( sortedTable, PS_LIST_TAIL, column_name, 0, NULL,
    290                        fill_F32_vector(psMetadataLookupVector(NULL, aTable, column_name), fillLength, sortedIndexVector, idets->n) );
    291   column_name = "EXT_INST_MAG";
    292   psMetadataAddVector( sortedTable, PS_LIST_TAIL, column_name, 0, NULL,
    293                        fill_F32_vector(psMetadataLookupVector(NULL, aTable, column_name), fillLength, sortedIndexVector, idets->n) );
    294   column_name = "EXT_INST_MAG_SIG";
    295   psMetadataAddVector( sortedTable, PS_LIST_TAIL, column_name, 0, NULL,
    296                        fill_F32_vector(psMetadataLookupVector(NULL, aTable, column_name), fillLength, sortedIndexVector, idets->n) );
    297   column_name = "NPARAMS";
    298   psMetadataAddVector( sortedTable, PS_LIST_TAIL, column_name, 0, NULL,
    299                        fill_F32_vector(psMetadataLookupVector(NULL, aTable, column_name), fillLength, sortedIndexVector, idets->n) );
    300   column_name = "EXT_WIDTH_MAJ";
    301   psMetadataAddVector( sortedTable, PS_LIST_TAIL, column_name, 0, NULL,
    302                        fill_F32_vector(psMetadataLookupVector(NULL, aTable, column_name), fillLength, sortedIndexVector, idets->n) );
    303   column_name = "EXT_WIDTH_MIN";
    304   psMetadataAddVector( sortedTable, PS_LIST_TAIL, column_name, 0, NULL,
    305                        fill_F32_vector(psMetadataLookupVector(NULL, aTable, column_name), fillLength, sortedIndexVector, idets->n) );
    306   column_name = "EXT_THETA";
    307   psMetadataAddVector( sortedTable, PS_LIST_TAIL, column_name, 0, NULL,
    308                        fill_F32_vector(psMetadataLookupVector(NULL, aTable, column_name), fillLength, sortedIndexVector, idets->n) );
    309   column_name = "EXT_WIDTH_MAJ_ERR";
    310   psMetadataAddVector( sortedTable, PS_LIST_TAIL, column_name, 0, NULL,
    311                        fill_F32_vector(psMetadataLookupVector(NULL, aTable, column_name), fillLength, sortedIndexVector, idets->n) );
    312   column_name = "EXT_WIDTH_MIN_ERR";
    313   psMetadataAddVector( sortedTable, PS_LIST_TAIL, column_name, 0, NULL,
    314                        fill_F32_vector(psMetadataLookupVector(NULL, aTable, column_name), fillLength, sortedIndexVector, idets->n) );
    315   column_name = "EXT_THETA_ERR";
    316   psMetadataAddVector( sortedTable, PS_LIST_TAIL, column_name, 0, NULL,
    317                        fill_F32_vector(psMetadataLookupVector(NULL, aTable, column_name), fillLength, sortedIndexVector, idets->n) );
    318   return sortedTable;
    319 }
    320 
    321 static psVector* fill_F32_vector(psVector* in, int length, long* indexes, int indexes_length) {
    322   if (in == NULL) {
    323     return NULL;
    324   }
    325   psVector* out = psVectorAlloc(length, in->type.type);
    326   int current_index = 0;
    327   for (int i = 0; i < indexes_length; i++) {
    328     while ( (current_index < indexes[i]) && (current_index < length) ) {
    329       out->data.F32[current_index] = NAN;
    330       current_index += 1;
    331     }
    332     out->data.F32[current_index] = in->data.F32[i];
    333     current_index += 1;
    334   }
    335   while ( current_index < length ) {
    336     out->data.F32[current_index] = NAN;
    337     current_index += 1;
    338   }
    339   return out;
    340 }
    341 
    342 static int compare (const void *a, const void *b) {
    343   return ( *((long*) a)-*((long*) b));
    344 }
    345 
    346 static long* sorted_idets_indexes(psVector *idets) {
    347   long* sortedIndexes = (long*) malloc(idets->n * sizeof(long));
    348   for (int i=0;i<idets->n;i++) {
    349     sortedIndexes[i] = idets->data.S64[i];
    350   }
    351   qsort(sortedIndexes, idets->n, sizeof(long), (void *) compare);
    352   return sortedIndexes;
    353 }
  • tags/ipp-20120802/ppTranslate/src/ppMopsWrite.c

    r34280 r34281  
    99#include "ppTranslateVersion.h"
    1010
    11 static bool addOutputColumn(psMetadata *table, const psArray *detections, long total, int extension, char *outColName, char *inColName, bool convertTo32);
     11static bool addOutputColumn(psMetadata *table, const psArray *detections, long total, char *outColName, char *inColName, bool convertTo32);
    1212static bool addSkyfileIDColumn(psMetadata *table, const psArray *detections, long total, char *colName);
    1313
    1414bool ppMopsWrite(const psArray *detections, const ppMopsArguments *args)
    1515{
    16   psFits *fits = psFitsOpen(args->output, "w"); // FITS file
    17   if (!fits) {
    18     psError(PS_ERR_IO, false, "Unable to open output file.");
    19     return false;
    20   }
    21 
    22   psMetadata *header = psMetadataAlloc(); // Header to write
    23   psString source = ppTranslateSource(), version = ppTranslateVersion();
    24   psMetadataAddStr(header, PS_LIST_TAIL, "SWSOURCE", 0, "Software source", source);
    25   psMetadataAddStr(header, PS_LIST_TAIL, "SWVERSN", 0, "Software version", version);
    26   ppTranslateVersionHeader(header);
    27   psFree(source);
    28   psFree(version);
    29 
    30   psMetadataAddStr(header, PS_LIST_TAIL, "EXP_NAME", 0, "Exposure name", args->exp_name);
    31   psMetadataAddS64(header, PS_LIST_TAIL, "EXP_ID", 0, "Exposure identifier", args->exp_id);
    32   psMetadataAddS64(header, PS_LIST_TAIL, "CHIP_ID", 0, "Chip stage identifier", args->chip_id);
    33   psMetadataAddS64(header, PS_LIST_TAIL, "CAM_ID", 0, "Cam stage identifier", args->cam_id);
    34   psMetadataAddS64(header, PS_LIST_TAIL, "FAKE_ID", 0, "Fake stage identifier", args->fake_id);
    35   psMetadataAddS64(header, PS_LIST_TAIL, "WARP_ID", 0, "Warp stage identifier", args->warp_id);
    36   psMetadataAddS64(header, PS_LIST_TAIL, "DIFF_ID", 0, "Diff stage identifier", args->diff_id);
    37   psMetadataAddBool(header, PS_LIST_TAIL, "DIFF_POS", 0, "Positive subtraction?", args->positive);
    38 
    39   // Get these header words from the first input non null input
    40   ppMopsDetections *det = NULL;
    41   for (int d = 0; d < detections->n && det == NULL; d++) {
    42     det = detections->data[d];
    43   }
    44   if (det != NULL) {
    45     psMetadataAddF64(header, PS_LIST_TAIL, "MJD-OBS", 0, "MJD of exposure midpoint", det->mjd);
    46     psMetadataAddStr(header, PS_LIST_TAIL, "RA", 0, "Right Ascension of boresight", det->raBoresight);
    47     psMetadataAddStr(header, PS_LIST_TAIL, "DEC", 0, "Declination of boresight", det->decBoresight);
    48     psMetadataAddF64(header, PS_LIST_TAIL, "TEL_ALT", 0, "Telescope altitude", det->alt);
    49     psMetadataAddF64(header, PS_LIST_TAIL, "TEL_AZ", 0, "Telescope azimuth", det->az);
    50     psMetadataAddF64(header, PS_LIST_TAIL, "EXPTIME", 0, "Exposure time (sec)", det->exptime);
    51     psMetadataAddF64(header, PS_LIST_TAIL, "ROTANGLE", 0, "Rotator position angle", det->posangle);
    52     psMetadataAddStr(header, PS_LIST_TAIL, "FILTER", 0, "Filter name", det->filter);
    53     psMetadataAddF32(header, PS_LIST_TAIL, "AIRMASS", 0, "Airmass of exposure", det->airmass);
    54     psMetadataAddF32(header, PS_LIST_TAIL, "SEEING", 0, "Mean seeing", det->seeing);
    55   } else {
    56     psWarning("no inputs with surviving detections. output header will be incomplete");
    57   }
    58   psMetadataAddStr(header, PS_LIST_TAIL, "OBSCODE", 0, "IAU Observatory code", OBSERVATORY_CODE);
    59   psMetadataAddF32(header, PS_LIST_TAIL, "MAGZP", 0, "Magnitude zero point", args->zp);
    60   psMetadataAddF32(header, PS_LIST_TAIL, "MAGZPERR", 0, "Error in magnitude zero point", args->zpErr);
    61   psMetadataAddF32(header, PS_LIST_TAIL, "ASTRORMS", 0, "RMS of astrometric fit", args->rmsAstrom);
    62 
    63   //field in header that tells about the CMF version
    64   char cmfVersion[8];
    65   sprintf(cmfVersion, PS1_DV_FORMAT, args->version);
    66   psMetadataAddStr(header, PS_LIST_TAIL, "CMFVERSION", 0, "CMF version", cmfVersion);
    67 
    68   // Find the total number of detections
    69 
    70   long total = 0;
    71   for (long i=0; i<detections->n; i++) {
    72     ppMopsDetections *det = detections->data[i];
    73     if (!det) {
    74       continue;
    75     }
    76     total += det->num;
    77   }
    78 
    79   psTrace("ppMops.write", 1, "Writing %ld rows to %s", total, args->output);
    80 
    81   if (total == 0) {
    82     // Write dummy table
    83     psMetadata *row = psMetadataAlloc(); // Output row
    84     psMetadataAddF64(row, PS_LIST_TAIL, "RA", 0, "Right ascension (degrees)", NAN);
    85     psMetadataAddF64(row, PS_LIST_TAIL, "RA_ERR", 0, "Right ascension error (degrees)", NAN);
    86     psMetadataAddF64(row, PS_LIST_TAIL, "DEC", 0, "Declination (degrees)", NAN);
    87     psMetadataAddF64(row, PS_LIST_TAIL, "DEC_ERR", 0, "Declination error (degrees)", NAN);
    88     psMetadataAddF32(row, PS_LIST_TAIL, "MAG", 0, "Magnitude", NAN);
    89     psMetadataAddF32(row, PS_LIST_TAIL, "MAG_ERR", 0, "Magnitude error", NAN);
    90     psMetadataAddF32(row, PS_LIST_TAIL, "PSF_CHI2", 0, "chi^2 of PSF fit", NAN);
    91     psMetadataAddS32(row, PS_LIST_TAIL, "PSF_DOF", 0, "Degrees of freedom of PSF fit", 0);
    92     psMetadataAddF32(row, PS_LIST_TAIL, "CR_SIGNIFICANCE", 0, "Significance of CR", NAN);
    93     psMetadataAddF32(row, PS_LIST_TAIL, "EXT_SIGNIFICANCE", 0, "Significance of extendedness", NAN);
    94     psMetadataAddF32(row, PS_LIST_TAIL, "PSF_MAJOR", 0, "PSF major axis (pixels)", NAN);
    95     psMetadataAddF32(row, PS_LIST_TAIL, "PSF_MINOR", 0, "PSF minor axis (pixels)", NAN);
    96     psMetadataAddF32(row, PS_LIST_TAIL, "PSF_THETA", 0, "PSF position angle (deg on chip)", NAN);
    97     psMetadataAddF32(row, PS_LIST_TAIL, "PSF_QUALITY", 0, "PSF quality factor", NAN);
    98     psMetadataAddS32(row, PS_LIST_TAIL, "PSF_NPIX", 0, "Number of pixels in PSF", 0);
    99     psMetadataAddF32(row, PS_LIST_TAIL, "MOMENTS_XX", 0, "xx moment", NAN);
    100     psMetadataAddF32(row, PS_LIST_TAIL, "MOMENTS_XY", 0, "xy moment", NAN);
    101     psMetadataAddF32(row, PS_LIST_TAIL, "MOMENTS_YY", 0, "yy moment", NAN);
    102     psMetadataAddU32(row, PS_LIST_TAIL, "FLAGS", 0, "Detection bit flags", 0);
    103     psMetadataAddS64(row, PS_LIST_TAIL, "DIFF_SKYFILE_ID", 0, "Identifier for diff skyfile", 0);
    104 
    105     psMetadataAddS32(row, PS_LIST_TAIL, "N_POS", 0, "Number of positive pixels", 0);
    106     psMetadataAddF32(row, PS_LIST_TAIL, "F_POS", 0, "Fraction of positive pixels", NAN);
    107     psMetadataAddF32(row, PS_LIST_TAIL, "RATIO_BAD", 0, "Ratio of positive pixels to negative", NAN);
    108     psMetadataAddF32(row, PS_LIST_TAIL, "RATIO_MASK", 0, "Ratio of positive pixels to masked", NAN);
    109     psMetadataAddF32(row, PS_LIST_TAIL, "RATIO_ALL", 0, "Ratio of positive pixels to all", NAN);
    110 
    111     if (args->version == 2) {
    112       // Write data of version 2 (see ICD)
    113       psMetadataAdd (row, PS_LIST_TAIL, "IPP_IDET",         PS_DATA_U32, "IPP detection identifier index",
    114                      NAN);
    115       psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_FLUX",    PS_DATA_F32, "PSF fit instrumental magnitude",
    116                      NAN);
    117       psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_FLUX_SIG",PS_DATA_F32, "Sigma of PSF instrumental magnitude",
    118                      NAN);
    119       psMetadataAdd (row, PS_LIST_TAIL, "AP_MAG",           PS_DATA_F32, "magnitude in standard aperture",
    120                      NAN);
    121       psMetadataAdd (row, PS_LIST_TAIL, "AP_MAG_RAW",       PS_DATA_F32, "magnitude in real aperture",
    122                      NAN);
    123       psMetadataAdd (row, PS_LIST_TAIL, "AP_MAG_RADIUS",    PS_DATA_F32, "radius used for aperture mags",
    124                      NAN);
    125       psMetadataAdd (row, PS_LIST_TAIL, "AP_FLUX",          PS_DATA_F32, "instrumental flux in standard aperture",
    126                      NAN);
    127       psMetadataAdd (row, PS_LIST_TAIL, "AP_FLUX_SIG",      PS_DATA_F32, "aperture flux error",
    128                      NAN);
    129       psMetadataAdd (row, PS_LIST_TAIL, "PEAK_FLUX_AS_MAG", PS_DATA_F32, "Peak flux expressed as magnitude",
    130                      NAN);
    131       psMetadataAdd (row, PS_LIST_TAIL, "CAL_PSF_MAG",      PS_DATA_F32, "PSF Magnitude using supplied calibration",
    132                      NAN);
    133       psMetadataAdd (row, PS_LIST_TAIL, "CAL_PSF_MAG_SIG",  PS_DATA_F32, "measured scatter of zero point calibration",
    134                      NAN);
    135       psMetadataAdd (row, PS_LIST_TAIL, "SKY",              PS_DATA_F32, "Sky level",
    136                      NAN);
    137       psMetadataAdd (row, PS_LIST_TAIL, "SKY_SIGMA",        PS_DATA_F32, "Sigma of sky level",
    138                      NAN);
    139       psMetadataAdd (row, PS_LIST_TAIL, "PSF_QF_PERFECT",   PS_DATA_F32, "PSF coverage/quality factor (poor)",
    140                      NAN);
    141       psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_R1",       PS_DATA_F32, "first radial moment",
    142                      NAN);
    143       psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_RH",       PS_DATA_F32, "half radial moment",
    144                      NAN);
    145       psMetadataAdd (row, PS_LIST_TAIL, "KRON_FLUX",        PS_DATA_F32, "Kron Flux (in 2.5 R1)",
    146                      NAN);
    147       psMetadataAdd (row, PS_LIST_TAIL, "KRON_FLUX_ERR",    PS_DATA_F32, "Kron Flux Error",
    148                      NAN);
    149       psMetadataAdd (row, PS_LIST_TAIL, "KRON_FLUX_INNER",  PS_DATA_F32, "Kron Flux (in 1.0 R1)",
    150                      NAN);
    151       psMetadataAdd (row, PS_LIST_TAIL, "KRON_FLUX_OUTER",  PS_DATA_F32, "Kron Flux (in 4.0 R1)",
    152                      NAN);
    153       psMetadataAdd (row, PS_LIST_TAIL, "DIFF_R_P",         PS_DATA_F32, "distance to positive match source",
    154                      NAN);
    155       psMetadataAdd (row, PS_LIST_TAIL, "DIFF_SN_P",        PS_DATA_F32, "signal-to-noise of pos match src",
    156                      NAN);
    157       psMetadataAdd (row, PS_LIST_TAIL, "DIFF_R_M",         PS_DATA_F32, "distance to negative match source",
    158                      NAN);
    159       psMetadataAdd (row, PS_LIST_TAIL, "DIFF_SN_M",        PS_DATA_F32, "signal-to-noise of neg match src",
    160                      NAN);
    161       psMetadataAdd (row, PS_LIST_TAIL, "FLAGS2",           PS_DATA_U32, "psphot analysis flags (group 2)",
    162                      0);
    163       psMetadataAdd (row, PS_LIST_TAIL, "N_FRAMES",         PS_DATA_U16, "Number of frames overlapping source center",
    164                      0);
    165       psMetadataAdd (row, PS_LIST_TAIL, "PADDING",          PS_DATA_S16, "padding",
    166                      0);
    167       if (args->version == 3) {
    168         // TODO: Write data of version 3 (see ICD)
    169       }
    170     }
    171 
    172     if (!psFitsWriteTableEmpty(fits, header, row, OUT_EXTNAME)) {
    173       psErrorStackPrint(stderr, "Unable to write empty table.");
    174       psFree(header);
    175       psFree(row);
    176       return false;
    177     }
    178     psFree(row);
    179   } else {
    180 
    181 #define addColumn(_outName, _inName, _convertTo32)                      \
    182     if (!addOutputColumn(table, detections, total, 0, _outName, _inName, _convertTo32)) { \
    183       psError(PS_ERR_UNKNOWN, false, "Failed to add column %s", _outName); \
    184       return false;                                                     \
    185     }
    186 
    187     // Allocate the output table
    188     psMetadata *table = psMetadataAlloc();
    189     addColumn("RA", "RA_PSF", 0);
    190     addColumn("RA_ERR", NULL, 0);      // calculated from various parameters including X_PSF_SIG Y_PSF_SIG and POSANG
    191     addColumn("DEC", "DEC_PSF", 0);
    192     addColumn("DEC_ERR", NULL, 0);     // calculated from various parameters including X_PSF_SIG Y_PSF_SIG and POSANG
    193     addColumn("MAG", "PSF_INST_MAG", 0);
    194     addColumn("MAG_ERR", "PSF_INST_MAG_SIG", 0);
    195     addColumn("PSF_CHI2", "PSF_CHISQ", 0);
    196     addColumn("PSF_DOF", "PSF_NDOF", 1);
    197     addColumn("CR_SIGNIFICANCE", "CR_NSIGMA", 0);
    198     addColumn("EXT_SIGNIFICANCE", "EXT_NSIGMA", 0);
    199     addColumn("PSF_MAJOR", NULL, 0);
    200     addColumn("PSF_MINOR", NULL, 0);     
    201     addColumn("PSF_THETA", NULL, 0);   
    202     addColumn("PSF_QUALITY", "PSF_QF", 0);
    203     addColumn("PSF_NPIX", NULL, 1);       
    204     addColumn("MOMENTS_XX", NULL, 0);
    205     addColumn("MOMENTS_XY", NULL, 0);
    206     addColumn("MOMENTS_YY", NULL, 0);
    207     addColumn("N_POS", "DIFF_NPOS", 1);
    208     addColumn("F_POS", "DIFF_FRATIO", 0);
    209     addColumn("RATIO_BAD", "DIFF_NRATIO_BAD", 0);
    210     addColumn("RATIO_MASK", "DIFF_NRATIO_MASK", 0);
    211     addColumn("RATIO_ALL", "DIFF_NRATIO_ALL", 0);
    212     addColumn("FLAGS", "FLAGS", 1);
    213     addSkyfileIDColumn(table, detections, total, "DIFF_SKYFILE_ID");
    214     if (args->version >= 2) {
    215       addColumn("IPP_IDET", NULL, 1);
    216       addColumn("PSF_INST_FLUX", NULL, 0);
    217       addColumn("PSF_INST_FLUX_SIG", NULL, 0);
    218       addColumn("AP_MAG", NULL, 0);
    219       addColumn("AP_MAG_RAW", NULL, 0);
    220       addColumn("AP_MAG_RADIUS", NULL, 0);
    221       addColumn("AP_FLUX", NULL, 0);
    222       addColumn("AP_FLUX_SIG", NULL, 0);
    223       addColumn("PEAK_FLUX_AS_MAG", NULL, 0);
    224       addColumn("CAL_PSF_MAG", NULL, 0);
    225       addColumn("CAL_PSF_MAG_SIG", NULL, 0);
    226       addColumn("SKY", NULL, 0);
    227       addColumn("SKY_SIGMA", NULL, 0);
    228       addColumn("PSF_QF_PERFECT", NULL, 0);
    229       addColumn("MOMENTS_R1", NULL, 0);
    230       addColumn("MOMENTS_RH", NULL, 0);
    231       addColumn("KRON_FLUX", NULL, 0);
    232       addColumn("KRON_FLUX_ERR", NULL, 0);
    233       addColumn("KRON_FLUX_INNER", NULL, 0);
    234       addColumn("KRON_FLUX_OUTER", NULL, 0);
    235       addColumn("DIFF_R_P", NULL, 0);
    236       addColumn("DIFF_SN_P", NULL, 0);
    237       addColumn("DIFF_R_M", NULL, 0);
    238       addColumn("DIFF_SN_M", NULL, 0);
    239       addColumn("FLAGS2", NULL, 1);
    240       addColumn("IPP_IDET", NULL, 0);
    241       addColumn("N_FRAMES", NULL, 0);
    242       addColumn("PADDING", NULL, 0);
    243       if (det->fittedTrails != NULL) {
    244 #define addFittedTrailColumn(_outName, _inName, _convertTo32)                   \
    245         if (!addOutputColumn(table, detections, total, 1, _outName, _inName, _convertTo32)) { \
    246           psTrace("ppMops.write", 1, "Failed to add column %s -> Replaced with NAN", _outName); \
     16
     17    psFits *fits = psFitsOpen(args->output, "w"); // FITS file
     18    if (!fits) {
     19        psError(PS_ERR_IO, false, "Unable to open output file.");
     20        return false;
     21    }
     22
     23    psMetadata *header = psMetadataAlloc(); // Header to write
     24    psString source = ppTranslateSource(), version = ppTranslateVersion();
     25    psMetadataAddStr(header, PS_LIST_TAIL, "SWSOURCE", 0, "Software source", source);
     26    psMetadataAddStr(header, PS_LIST_TAIL, "SWVERSN", 0, "Software version", version);
     27    ppTranslateVersionHeader(header);
     28    psFree(source);
     29    psFree(version);
     30
     31    psMetadataAddStr(header, PS_LIST_TAIL, "EXP_NAME", 0, "Exposure name", args->exp_name);
     32    psMetadataAddS64(header, PS_LIST_TAIL, "EXP_ID", 0, "Exposure identifier", args->exp_id);
     33    psMetadataAddS64(header, PS_LIST_TAIL, "CHIP_ID", 0, "Chip stage identifier", args->chip_id);
     34    psMetadataAddS64(header, PS_LIST_TAIL, "CAM_ID", 0, "Cam stage identifier", args->cam_id);
     35    psMetadataAddS64(header, PS_LIST_TAIL, "FAKE_ID", 0, "Fake stage identifier", args->fake_id);
     36    psMetadataAddS64(header, PS_LIST_TAIL, "WARP_ID", 0, "Warp stage identifier", args->warp_id);
     37    psMetadataAddS64(header, PS_LIST_TAIL, "DIFF_ID", 0, "Diff stage identifier", args->diff_id);
     38    psMetadataAddBool(header, PS_LIST_TAIL, "DIFF_POS", 0, "Positive subtraction?", args->positive);
     39
     40    // Get these header words from the first input non null input
     41    ppMopsDetections *det = NULL;
     42    for (int d = 0; d < detections->n && det == NULL; d++) {
     43        det = detections->data[d];
     44    }
     45    if (det != NULL) {
     46        psMetadataAddF64(header, PS_LIST_TAIL, "MJD-OBS", 0, "MJD of exposure midpoint", det->mjd);
     47        psMetadataAddStr(header, PS_LIST_TAIL, "RA", 0, "Right Ascension of boresight", det->raBoresight);
     48        psMetadataAddStr(header, PS_LIST_TAIL, "DEC", 0, "Declination of boresight", det->decBoresight);
     49        psMetadataAddF64(header, PS_LIST_TAIL, "TEL_ALT", 0, "Telescope altitude", det->alt);
     50        psMetadataAddF64(header, PS_LIST_TAIL, "TEL_AZ", 0, "Telescope azimuth", det->az);
     51        psMetadataAddF64(header, PS_LIST_TAIL, "EXPTIME", 0, "Exposure time (sec)", det->exptime);
     52        psMetadataAddF64(header, PS_LIST_TAIL, "ROTANGLE", 0, "Rotator position angle", det->posangle);
     53        psMetadataAddStr(header, PS_LIST_TAIL, "FILTER", 0, "Filter name", det->filter);
     54        psMetadataAddF32(header, PS_LIST_TAIL, "AIRMASS", 0, "Airmass of exposure", det->airmass);
     55        psMetadataAddF32(header, PS_LIST_TAIL, "SEEING", 0, "Mean seeing", det->seeing);
     56    } else {
     57        psWarning("no inputs with surviving detections. output header will be incomplete");
     58    }
     59    psMetadataAddStr(header, PS_LIST_TAIL, "OBSCODE", 0, "IAU Observatory code", OBSERVATORY_CODE);
     60    psMetadataAddF32(header, PS_LIST_TAIL, "MAGZP", 0, "Magnitude zero point", args->zp);
     61    psMetadataAddF32(header, PS_LIST_TAIL, "MAGZPERR", 0, "Error in magnitude zero point", args->zpErr);
     62    psMetadataAddF32(header, PS_LIST_TAIL, "ASTRORMS", 0, "RMS of astrometric fit", args->rmsAstrom);
     63
     64    //field in header that tells about the CMF version
     65    char cmfVersion[8];
     66    sprintf(cmfVersion, PS1_DV_FORMAT, args->version);
     67    psMetadataAddStr(header, PS_LIST_TAIL, "CMFVERSION", 0, "CMF version", cmfVersion);
     68
     69    // Find the total number of detections
     70
     71    long total = 0;
     72    for (long i=0; i<detections->n; i++) {
     73        ppMopsDetections *det = detections->data[i];
     74        if (!det) {
     75            continue;
    24776        }
    248         addFittedTrailColumn("X_EXT", NULL, 0);
    249         addFittedTrailColumn("Y_EXT", NULL, 0);
    250         addFittedTrailColumn("X_EXT_SIG", NULL, 0);
    251         addFittedTrailColumn("Y_EXT_SIG", NULL, 0);
    252         addFittedTrailColumn("EXT_INST_MAG", NULL, 0);
    253         addFittedTrailColumn("EXT_INST_MAG_SIG", NULL, 0);
    254         addFittedTrailColumn("NPARAMS", NULL, 0);
    255         addFittedTrailColumn("EXT_WIDTH_MAJ", NULL, 0);
    256         addFittedTrailColumn("EXT_WIDTH_MIN", NULL, 0);
    257         addFittedTrailColumn("EXT_THETA", NULL, 0);
    258         addFittedTrailColumn("EXT_WIDTH_MAJ_ERR", NULL, 0);
    259         addFittedTrailColumn("EXT_WIDTH_MIN_ERR", NULL, 0);
    260         addFittedTrailColumn("EXT_THETA_ERR", NULL, 0);
    261       }
    262     }
    263     if (!psFitsWriteTableAllColumns(fits, header, table, OUT_EXTNAME)) {
    264       psError(psErrorCodeLast(), false, "Unable to write table");
    265       return false;
    266     }
    267     psFree(table);
    268   }
    269 
    270   psFree(header);
    271   psFitsClose(fits);
    272 
    273   psTrace("ppMops.write", 1, "Done writing %ld rows to %s", det->num, args->output);
    274 
    275   return true;
     77        total += det->num;
     78    }
     79
     80    psTrace("ppMops.write", 1, "Writing %ld rows to %s", total, args->output);
     81
     82    if (total == 0) {
     83        // Write dummy table
     84        psMetadata *row = psMetadataAlloc(); // Output row
     85        psMetadataAddF64(row, PS_LIST_TAIL, "RA", 0, "Right ascension (degrees)", NAN);
     86        psMetadataAddF64(row, PS_LIST_TAIL, "RA_ERR", 0, "Right ascension error (degrees)", NAN);
     87        psMetadataAddF64(row, PS_LIST_TAIL, "DEC", 0, "Declination (degrees)", NAN);
     88        psMetadataAddF64(row, PS_LIST_TAIL, "DEC_ERR", 0, "Declination error (degrees)", NAN);
     89        psMetadataAddF32(row, PS_LIST_TAIL, "MAG", 0, "Magnitude", NAN);
     90        psMetadataAddF32(row, PS_LIST_TAIL, "MAG_ERR", 0, "Magnitude error", NAN);
     91        psMetadataAddF32(row, PS_LIST_TAIL, "PSF_CHI2", 0, "chi^2 of PSF fit", NAN);
     92        psMetadataAddS32(row, PS_LIST_TAIL, "PSF_DOF", 0, "Degrees of freedom of PSF fit", 0);
     93        psMetadataAddF32(row, PS_LIST_TAIL, "CR_SIGNIFICANCE", 0, "Significance of CR", NAN);
     94        psMetadataAddF32(row, PS_LIST_TAIL, "EXT_SIGNIFICANCE", 0, "Significance of extendedness", NAN);
     95        psMetadataAddF32(row, PS_LIST_TAIL, "PSF_MAJOR", 0, "PSF major axis (pixels)", NAN);
     96        psMetadataAddF32(row, PS_LIST_TAIL, "PSF_MINOR", 0, "PSF minor axis (pixels)", NAN);
     97        psMetadataAddF32(row, PS_LIST_TAIL, "PSF_THETA", 0, "PSF position angle (deg on chip)", NAN);
     98        psMetadataAddF32(row, PS_LIST_TAIL, "PSF_QUALITY", 0, "PSF quality factor", NAN);
     99        psMetadataAddS32(row, PS_LIST_TAIL, "PSF_NPIX", 0, "Number of pixels in PSF", 0);
     100        psMetadataAddF32(row, PS_LIST_TAIL, "MOMENTS_XX", 0, "xx moment", NAN);
     101        psMetadataAddF32(row, PS_LIST_TAIL, "MOMENTS_XY", 0, "xy moment", NAN);
     102        psMetadataAddF32(row, PS_LIST_TAIL, "MOMENTS_YY", 0, "yy moment", NAN);
     103        psMetadataAddU32(row, PS_LIST_TAIL, "FLAGS", 0, "Detection bit flags", 0);
     104        psMetadataAddS64(row, PS_LIST_TAIL, "DIFF_SKYFILE_ID", 0, "Identifier for diff skyfile", 0);
     105
     106        psMetadataAddS32(row, PS_LIST_TAIL, "N_POS", 0, "Number of positive pixels", 0);
     107        psMetadataAddF32(row, PS_LIST_TAIL, "F_POS", 0, "Fraction of positive pixels", NAN);
     108        psMetadataAddF32(row, PS_LIST_TAIL, "RATIO_BAD", 0, "Ratio of positive pixels to negative", NAN);
     109        psMetadataAddF32(row, PS_LIST_TAIL, "RATIO_MASK", 0, "Ratio of positive pixels to masked", NAN);
     110        psMetadataAddF32(row, PS_LIST_TAIL, "RATIO_ALL", 0, "Ratio of positive pixels to all", NAN);
     111
     112        if (args->version == 2) {
     113              // Write data of version 2 (see ICD)
     114              psMetadataAdd (row, PS_LIST_TAIL, "IPP_IDET",         PS_DATA_U32, "IPP detection identifier index",
     115                             NAN);
     116              psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_FLUX",    PS_DATA_F32, "PSF fit instrumental magnitude",
     117                             NAN);
     118              psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_FLUX_SIG",PS_DATA_F32, "Sigma of PSF instrumental magnitude",
     119                             NAN);
     120              psMetadataAdd (row, PS_LIST_TAIL, "AP_MAG",           PS_DATA_F32, "magnitude in standard aperture",
     121                             NAN);
     122              psMetadataAdd (row, PS_LIST_TAIL, "AP_MAG_RAW",       PS_DATA_F32, "magnitude in real aperture",
     123                             NAN);
     124              psMetadataAdd (row, PS_LIST_TAIL, "AP_MAG_RADIUS",    PS_DATA_F32, "radius used for aperture mags",
     125                             NAN);
     126              psMetadataAdd (row, PS_LIST_TAIL, "AP_FLUX",          PS_DATA_F32, "instrumental flux in standard aperture",
     127                             NAN);
     128              psMetadataAdd (row, PS_LIST_TAIL, "AP_FLUX_SIG",      PS_DATA_F32, "aperture flux error",
     129                             NAN);
     130              psMetadataAdd (row, PS_LIST_TAIL, "PEAK_FLUX_AS_MAG", PS_DATA_F32, "Peak flux expressed as magnitude",
     131                             NAN);
     132              psMetadataAdd (row, PS_LIST_TAIL, "CAL_PSF_MAG",      PS_DATA_F32, "PSF Magnitude using supplied calibration",
     133                             NAN);
     134              psMetadataAdd (row, PS_LIST_TAIL, "CAL_PSF_MAG_SIG",  PS_DATA_F32, "measured scatter of zero point calibration",
     135                             NAN);
     136              psMetadataAdd (row, PS_LIST_TAIL, "SKY",              PS_DATA_F32, "Sky level",
     137                             NAN);
     138              psMetadataAdd (row, PS_LIST_TAIL, "SKY_SIGMA",        PS_DATA_F32, "Sigma of sky level",
     139                             NAN);
     140              psMetadataAdd (row, PS_LIST_TAIL, "PSF_QF_PERFECT",   PS_DATA_F32, "PSF coverage/quality factor (poor)",
     141                             NAN);
     142              psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_R1",       PS_DATA_F32, "first radial moment",
     143                             NAN);
     144              psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_RH",       PS_DATA_F32, "half radial moment",
     145                             NAN);
     146              psMetadataAdd (row, PS_LIST_TAIL, "KRON_FLUX",        PS_DATA_F32, "Kron Flux (in 2.5 R1)",
     147                             NAN);
     148              psMetadataAdd (row, PS_LIST_TAIL, "KRON_FLUX_ERR",    PS_DATA_F32, "Kron Flux Error",
     149                             NAN);
     150              psMetadataAdd (row, PS_LIST_TAIL, "KRON_FLUX_INNER",  PS_DATA_F32, "Kron Flux (in 1.0 R1)",
     151                             NAN);
     152              psMetadataAdd (row, PS_LIST_TAIL, "KRON_FLUX_OUTER",  PS_DATA_F32, "Kron Flux (in 4.0 R1)",
     153                             NAN);
     154              psMetadataAdd (row, PS_LIST_TAIL, "DIFF_R_P",         PS_DATA_F32, "distance to positive match source",
     155                             NAN);
     156              psMetadataAdd (row, PS_LIST_TAIL, "DIFF_SN_P",        PS_DATA_F32, "signal-to-noise of pos match src",
     157                             NAN);
     158              psMetadataAdd (row, PS_LIST_TAIL, "DIFF_R_M",         PS_DATA_F32, "distance to negative match source",
     159                             NAN);
     160              psMetadataAdd (row, PS_LIST_TAIL, "DIFF_SN_M",        PS_DATA_F32, "signal-to-noise of neg match src",
     161                             NAN);
     162              psMetadataAdd (row, PS_LIST_TAIL, "FLAGS2",           PS_DATA_U32, "psphot analysis flags (group 2)",
     163                             0);
     164              psMetadataAdd (row, PS_LIST_TAIL, "N_FRAMES",         PS_DATA_U16, "Number of frames overlapping source center",
     165                             0);
     166              psMetadataAdd (row, PS_LIST_TAIL, "PADDING",          PS_DATA_S16, "padding",
     167                             0);
     168        }
     169
     170        if (!psFitsWriteTableEmpty(fits, header, row, OUT_EXTNAME)) {
     171            psErrorStackPrint(stderr, "Unable to write empty table.");
     172            psFree(header);
     173            psFree(row);
     174            return false;
     175        }
     176        psFree(row);
     177    } else {
     178
     179#define addColumn(_outName, _inName, _convertTo32) \
     180        if (!addOutputColumn(table, detections, total, _outName, _inName, _convertTo32)) { \
     181            psError(PS_ERR_UNKNOWN, false, "Failed to add column %s", _outName); \
     182            return false; \
     183        }
     184
     185        // Allocate the output table
     186        psMetadata *table = psMetadataAlloc();
     187        addColumn("RA", "RA_PSF", 0);
     188        addColumn("RA_ERR", NULL, 0);      // calculated from various parameters including X_PSF_SIG Y_PSF_SIG and POSANG
     189        addColumn("DEC", "DEC_PSF", 0);
     190        addColumn("DEC_ERR", NULL, 0);     // calculated from various parameters including X_PSF_SIG Y_PSF_SIG and POSANG
     191        addColumn("MAG", "PSF_INST_MAG", 0);
     192        addColumn("MAG_ERR", "PSF_INST_MAG_SIG", 0);
     193        addColumn("PSF_CHI2", "PSF_CHISQ", 0);
     194        addColumn("PSF_DOF", "PSF_NDOF", 1);
     195        addColumn("CR_SIGNIFICANCE", "CR_NSIGMA", 0);
     196        addColumn("EXT_SIGNIFICANCE", "EXT_NSIGMA", 0);
     197        addColumn("PSF_MAJOR", NULL, 0);
     198        addColumn("PSF_MINOR", NULL, 0);     
     199        addColumn("PSF_THETA", NULL, 0);   
     200        addColumn("PSF_QUALITY", "PSF_QF", 0);
     201        addColumn("PSF_NPIX", NULL, 1);       
     202        addColumn("MOMENTS_XX", NULL, 0);
     203        addColumn("MOMENTS_XY", NULL, 0);
     204        addColumn("MOMENTS_YY", NULL, 0);
     205        addColumn("N_POS", "DIFF_NPOS", 1);
     206        addColumn("F_POS", "DIFF_FRATIO", 0);
     207        addColumn("RATIO_BAD", "DIFF_NRATIO_BAD", 0);
     208        addColumn("RATIO_MASK", "DIFF_NRATIO_MASK", 0);
     209        addColumn("RATIO_ALL", "DIFF_NRATIO_ALL", 0);
     210        addColumn("FLAGS", "FLAGS", 1);
     211        addSkyfileIDColumn(table, detections, total, "DIFF_SKYFILE_ID");
     212        if (args->version == 2) {
     213            addColumn("IPP_IDET", NULL, 1);
     214            addColumn("PSF_INST_FLUX", NULL, 0);
     215            addColumn("PSF_INST_FLUX_SIG", NULL, 0);
     216            addColumn("AP_MAG", NULL, 0);
     217            addColumn("AP_MAG_RAW", NULL, 0);
     218            addColumn("AP_MAG_RADIUS", NULL, 0);
     219            addColumn("AP_FLUX", NULL, 0);
     220            addColumn("AP_FLUX_SIG", NULL, 0);
     221            addColumn("PEAK_FLUX_AS_MAG", NULL, 0);
     222            addColumn("CAL_PSF_MAG", NULL, 0);
     223            addColumn("CAL_PSF_MAG_SIG", NULL, 0);
     224            addColumn("SKY", NULL, 0);
     225            addColumn("SKY_SIGMA", NULL, 0);
     226            addColumn("PSF_QF_PERFECT", NULL, 0);
     227            addColumn("MOMENTS_R1", NULL, 0);
     228            addColumn("MOMENTS_RH", NULL, 0);
     229            addColumn("KRON_FLUX", NULL, 0);
     230            addColumn("KRON_FLUX_ERR", NULL, 0);
     231            addColumn("KRON_FLUX_INNER", NULL, 0);
     232            addColumn("KRON_FLUX_OUTER", NULL, 0);
     233            addColumn("DIFF_R_P", NULL, 0);
     234            addColumn("DIFF_SN_P", NULL, 0);
     235            addColumn("DIFF_R_M", NULL, 0);
     236            addColumn("DIFF_SN_M", NULL, 0);
     237            addColumn("FLAGS2", NULL, 1);
     238            addColumn("IPP_IDET", NULL, 0);
     239            addColumn("N_FRAMES", NULL, 0);
     240            addColumn("PADDING", NULL, 0);
     241        }
     242        if (!psFitsWriteTableAllColumns(fits, header, table, OUT_EXTNAME)) {
     243            psError(psErrorCodeLast(), false, "Unable to write table");
     244            return false;
     245        }
     246        psFree(table);
     247    }
     248
     249    psFree(header);
     250    psFitsClose(fits);
     251
     252    psTrace("ppMops.write", 1, "Done writing %ld rows to %s", det->num, args->output);
     253
     254    return true;
    276255}
    277256
    278 // extension parameter values:
    279 // 0: SkyChip.psf
    280 // 1: SkyChip.xfit
    281 // Any other value is ignored
    282 static bool addOutputColumn(psMetadata *table, const psArray *detections, long outputSize, int extension, char *outColumnName, char *inColumnName, bool convertTo32)
     257static bool addOutputColumn(psMetadata *table, const psArray *detections, long outputSize, char *outColumnName, char *inColumnName, bool convertTo32)
    283258{
    284   if (inColumnName == NULL) {
    285     inColumnName = outColumnName;
    286   }
    287   psVector *out = NULL;
    288   if (convertTo32) {
    289     // psFitsReadTableAllColumns reads columns of cfitsio type LONG and ULONG into a 64 bit integers
    290     // We want to write 32 bits to the output.
    291     int next = 0;
    292     for (long i=0; i<detections->n; i++) {
    293       ppMopsDetections *det = detections->data[i];
    294       if (!det || det->num == 0) {
    295         // no detections survived for this input
    296         continue;
    297       }
    298       psVector *in = NULL;
    299       if (extension == 0) {
    300         in = psMetadataLookupVector(NULL, det->table, inColumnName);
    301       } else if (extension == 1) {
    302         in = psMetadataLookupVector(NULL, det->fittedTrails, inColumnName);
    303       } else {
    304         //Error?
    305       }
    306       if (!in) {
    307         psError(PS_ERR_PROGRAMMING, true, "failed to find input column: %s (convertTo32 is true)", inColumnName);
    308         return false;
    309       }
    310       if (in->type.type != PS_TYPE_S64 && in->type.type != PS_TYPE_U64) {
    311         psError(PS_ERR_PROGRAMMING, true, "input column to convert is not S64 or U64: %s %d",
    312                 inColumnName, in->type.type);
    313         return false;
    314       }
    315       if (out == NULL) {
    316         // First time through set up the output vector and the copy parameters
    317         if (in->type.type == PS_TYPE_S64) {
    318           out = psVectorAlloc(outputSize, PS_TYPE_S32);
    319         } else {
    320           out = psVectorAlloc(outputSize, PS_TYPE_U32);
    321         }
    322       }
    323       for (long d=0; d < det->num; d++) {
    324         if (in->type.type == PS_TYPE_S64) {
    325           out->data.S32[next++] = in->data.S64[d];
    326         } else {
    327           out->data.U32[next++] = in->data.U64[d];
    328         }
    329       }
    330     }
    331   } else {
    332     void *next = NULL;
    333     int elementSize = 0;    // size of elements in vector... We are making assumptions here about the organization of primitives in memory so we can use memcopy
    334     for (long i=0; i<detections->n; i++) {
    335       ppMopsDetections *det = detections->data[i];
    336       if (!det || det->num == 0) {
    337         // no detections survived for this input
    338         continue;
    339       }
    340       psVector *in = NULL;
    341       if (extension == 0) {
    342         psTrace("ppMops.write", 1, "Using det->table for %s", inColumnName);
    343         in = psMetadataLookupVector(NULL, det->table, inColumnName);
    344       } else if (extension == 1) {
    345         psTrace("ppMops.write", 1, "Using det->fittedTrails for %s", inColumnName);
    346         in = psMetadataLookupVector(NULL, det->fittedTrails, inColumnName);
    347       } else {
    348         //Error?
    349       }
    350       if (!in) {
    351         psError(PS_ERR_PROGRAMMING, true, "failed to find input column: %s (convertTo32 is false)", inColumnName);
    352         out = psVectorAlloc(outputSize, PS_TYPE_F32);
    353         psVectorInit(out, NAN);
    354         psMetadataAddVector(table, PS_LIST_TAIL, outColumnName, 0, NULL, out);
    355         return false;
    356       }
    357       if (out == NULL) {
    358         // First time through set up the output vector and the copy parameters
    359         out = psVectorAlloc(outputSize, in->type.type);
    360         next = (void *) out->data.U8;
    361         switch (in->type.type) {
    362         case PS_TYPE_S8:
    363           elementSize = sizeof(psS8);
    364           break;
    365         case PS_TYPE_U8:
    366           elementSize = sizeof(psU8);
    367           break;
    368         case PS_TYPE_S16:
    369           elementSize = sizeof(psS16);
    370           break;
    371         case PS_TYPE_U16:
    372           elementSize = sizeof(psU16);
    373           break;
    374         case PS_TYPE_S32:
    375           elementSize = sizeof(psS32);
    376           break;
    377         case PS_TYPE_U32:
    378           elementSize = sizeof(psU32);
    379           break;
    380         case PS_TYPE_S64:
    381           elementSize = sizeof(psS64);
    382           break;
    383         case PS_TYPE_U64:
    384           elementSize = sizeof(psU64);
    385           break;
    386         case PS_TYPE_F32:
    387           elementSize = sizeof(psF32);
    388           break;
    389         case PS_TYPE_F64:
    390           elementSize = sizeof(psF64);
    391           break;
    392         default:
    393           psError(PS_ERR_BAD_PARAMETER_TYPE, true, "Unknown vector type %d", in->type.type);
    394           return false;
    395         }
    396       }
    397       // We are doing nasty things here so we can use memcpy.
    398       // It would be safer to do a proper loop over the elements.
    399       long toCopy = det->num * elementSize;
    400       memcpy(next, in->data.U8, toCopy);
    401       next += toCopy;
    402     }
    403   }
    404   // Finally add the new column to the output table
    405   psMetadataAddVector(table, PS_LIST_TAIL, outColumnName, 0, NULL, out);
    406   psFree(out);    // drop reference
    407   return true;
     259    if (inColumnName == NULL) {
     260        inColumnName = outColumnName;
     261    }
     262
     263    psVector *out = NULL;
     264    if (convertTo32) {
     265        // psFitsReadTableAllColumns reads columns of cfitsio type LONG and ULONG into a 64 bit integers
     266        // We want to write 32 bits to the output.
     267        int next = 0;
     268        for (long i=0; i<detections->n; i++) {
     269            ppMopsDetections *det = detections->data[i];
     270            if (!det || det->num == 0) {
     271                // no detections survived for this input
     272                continue;
     273            }
     274            psVector *in = psMetadataLookupVector(NULL, det->table, inColumnName);
     275            if (!in) {
     276                psError(PS_ERR_PROGRAMMING, true, "failed to find input column: %s", inColumnName);
     277                return false;
     278            }
     279            if (in->type.type != PS_TYPE_S64 && in->type.type != PS_TYPE_U64) {
     280                psError(PS_ERR_PROGRAMMING, true, "input column to convert is not S64 or U64: %s %d",
     281                    inColumnName, in->type.type);
     282                return false;
     283            }
     284            if (out == NULL) {
     285                // First time through set up the output vector and the copy parameters
     286                if (in->type.type == PS_TYPE_S64) {
     287                    out = psVectorAlloc(outputSize, PS_TYPE_S32);
     288                } else {
     289                    out = psVectorAlloc(outputSize, PS_TYPE_U32);
     290                }
     291            }
     292            for (long d=0; d < det->num; d++) {
     293                if (in->type.type == PS_TYPE_S64) {
     294                    out->data.S32[next++] = in->data.S64[d];
     295                } else {
     296                    out->data.U32[next++] = in->data.U64[d];
     297                }
     298            }
     299        }
     300    } else {
     301        void *next = NULL;
     302        int elementSize = 0;    // size of elements in vector... We are making assumptions here about the organization of primitives in memory so we can use memcopy
     303        for (long i=0; i<detections->n; i++) {
     304            ppMopsDetections *det = detections->data[i];
     305            if (!det || det->num == 0) {
     306                // no detections survived for this input
     307                continue;
     308            }
     309            psVector *in = psMetadataLookupVector(NULL, det->table, inColumnName);
     310            if (!in) {
     311                psError(PS_ERR_PROGRAMMING, true, "failed to find input column: %s", inColumnName);
     312                return false;
     313            }
     314            if (out == NULL) {
     315                // First time through set up the output vector and the copy parameters
     316                out = psVectorAlloc(outputSize, in->type.type);
     317                next = (void *) out->data.U8;
     318                switch (in->type.type) {
     319                    case PS_TYPE_S8:
     320                    elementSize = sizeof(psS8);
     321                    break;
     322                case PS_TYPE_U8:
     323                    elementSize = sizeof(psU8);
     324                    break;
     325                case PS_TYPE_S16:
     326                    elementSize = sizeof(psS16);
     327                    break;
     328                case PS_TYPE_U16:
     329                    elementSize = sizeof(psU16);
     330                    break;
     331                case PS_TYPE_S32:
     332                    elementSize = sizeof(psS32);
     333                    break;
     334                case PS_TYPE_U32:
     335                    elementSize = sizeof(psU32);
     336                    break;
     337                case PS_TYPE_S64:
     338                    elementSize = sizeof(psS64);
     339                    break;
     340                case PS_TYPE_U64:
     341                    elementSize = sizeof(psU64);
     342                    break;
     343                case PS_TYPE_F32:
     344                    elementSize = sizeof(psF32);
     345                    break;
     346                case PS_TYPE_F64:
     347                    elementSize = sizeof(psF64);
     348                    break;
     349                default:
     350                    psError(PS_ERR_BAD_PARAMETER_TYPE, true, "Unknown vector type %d", in->type.type);
     351                    return false;
     352
     353                }
     354            }
     355            // We are doing nasty things here so we can use memcpy.
     356            // It would be safer to do a proper loop over the elements.
     357            long toCopy = det->num * elementSize;
     358            memcpy(next, in->data.U8, toCopy);
     359            next += toCopy;
     360        }
     361    }
     362
     363    // Finally add the new column to the output table
     364    psMetadataAddVector(table, PS_LIST_TAIL, outColumnName, 0, NULL, out);
     365    psFree(out);    // drop reference
     366
     367    return true;
    408368}
    409 
    410369static bool addSkyfileIDColumn(psMetadata *table, const psArray *detections, long total, char *colName)
    411370{
    412   psVector *out = psVectorAlloc(total, PS_TYPE_S64);
    413   long next = 0;
    414   for (long i = 0; i<detections->n; i++) {
    415     ppMopsDetections *det = detections->data[i];
    416     if (!det) {
    417       continue;
    418     }
    419     psS64 diffSkyfileId = det->diffSkyfileId;
    420     for (long j = 0; j < det->num; j++) {
    421       out->data.S64[next++] = diffSkyfileId;
    422     }
    423   }
    424   psMetadataAddVector(table, PS_LIST_TAIL, colName, 0, NULL, out);
    425   psFree(out);
    426   return true;
     371    psVector *out = psVectorAlloc(total, PS_TYPE_S64);
     372    long next = 0;
     373    for (long i = 0; i<detections->n; i++) {
     374        ppMopsDetections *det = detections->data[i];
     375        if (!det) {
     376            continue;
     377        }
     378        psS64 diffSkyfileId = det->diffSkyfileId;
     379        for (long j = 0; j < det->num; j++) {
     380            out->data.S64[next++] = diffSkyfileId;
     381        }
     382    }
     383    psMetadataAddVector(table, PS_LIST_TAIL, colName, 0, NULL, out);
     384    psFree(out);
     385    return true;
    427386}
Note: See TracChangeset for help on using the changeset viewer.