IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Ignore:
Timestamp:
Feb 8, 2023, 11:54:08 AM (3 years ago)
Author:
eugene
Message:

merge from eam_branches/ipp-20220316. no_warn strncpy; avoid passing NULL to sprintf %s; add code for PATTERN_DEAD_CELLS; fix error in PSF residual image evaluation; drop detailed mask analysis for binned images (not actually used)

Location:
trunk/psModules
Files:
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/psModules

  • trunk/psModules/src/detrend/pmDark.c

    r40454 r42379  
    129129    } else {
    130130        if (!ordinateParseConcept(value, readout, name)) {
    131             psError(PM_ERR_CONFIG, false, "trouble parsing rule %s for DARK.ORDINATE %s", rule, name);
     131            psError(PM_ERR_CONFIG, false, "trouble parsing rule %s for DARK.ORDINATE %s", "NULL", name);
    132132            return false;
    133133        }
  • trunk/psModules/src/detrend/pmDetrendDB.c

    r41892 r42379  
    113113        DETREND_STRING_CASE(KH_CORRECT);
    114114        DETREND_STRING_CASE(PATTERN_ROW_AMP);
     115        DETREND_STRING_CASE(PATTERN_DEAD_CELLS);
    115116    default:
    116117        return NULL;
  • trunk/psModules/src/detrend/pmDetrendDB.h

    r42338 r42379  
    4343    PM_DETREND_TYPE_KH_CORRECT,
    4444    PM_DETREND_TYPE_PATTERN_ROW_AMP,
     45    PM_DETREND_TYPE_PATTERN_DEAD_CELLS,
    4546} pmDetrendType;
    4647
  • trunk/psModules/src/detrend/pmOverscan.c

    r42356 r42379  
    3838    opts->order = order;
    3939    opts->stat = psMemIncrRefCounter(stat);
     40
     41    opts->minValid = 0.0; // default value if not defined
     42    opts->maxValid = (float) 0x10000; // default value if not defined
     43    opts->maskVal = 0x0001; // default value if not defined
    4044
    4145    // Smoothing
     
    314318        psFree(reducedScalar);
    315319
     320        // EAM 2022.03.29 : if the calculated overscan value is below the threshold,
     321        // declare the readout dead and mask
     322
     323        if ((reduced < overscanOpts->minValid) || (reduced > overscanOpts->maxValid)) {
     324            fprintf (stderr, "bad overscan (1) %f, masking readout\n", reduced);
     325            psImage *mask = input->mask;
     326            for (int y = 0; y < mask->numRows; y++) {
     327                for (int x = 0; x < mask->numCols; x++) {
     328                    mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] |= overscanOpts->maskVal;
     329                }
     330            }
     331        }
     332
    316333        psFree(stats);
    317334        return true;
     
    371388        // generate stats of overscan vector for header
    372389        {
    373           psString comment = NULL;    // Comment to add
    374           psStats *vectorStats = psStatsAlloc (PS_STAT_SAMPLE_MEAN | PS_STAT_SAMPLE_STDEV);
    375           if (!psVectorStats (vectorStats, reduced, NULL, NULL, 0)) {
    376               psError(PS_ERR_UNKNOWN, false, "failure to measure stats");
    377               return false;
    378           }
    379           psStringAppend(&comment, "Mean Overscan value: %f", vectorStats->sampleMean);
    380           psMetadataAddStr(hdu->header, PS_LIST_TAIL, "HISTORY", PS_META_DUPLICATE_OK, comment, "");
    381           psFree(comment);
    382 
    383           // write metadata header value
    384           psMetadataAddF32(hdu->header, PS_LIST_TAIL, "OVER_VAL", PS_META_REPLACE, "Overscan mean", vectorStats->sampleMean);
    385           psMetadataAddF32(hdu->header, PS_LIST_TAIL, "OVER_SIG", PS_META_REPLACE, "Overscan stdev", vectorStats->sampleStdev);
    386           psFree (vectorStats);
     390            psString comment = NULL;    // Comment to add
     391            psStats *vectorStats = psStatsAlloc (PS_STAT_SAMPLE_MEAN | PS_STAT_SAMPLE_STDEV);
     392            if (!psVectorStats (vectorStats, reduced, NULL, NULL, 0)) {
     393                psError(PS_ERR_UNKNOWN, false, "failure to measure stats");
     394                return false;
     395            }
     396            psStringAppend(&comment, "Mean Overscan value: %f", vectorStats->sampleMean);
     397            psMetadataAddStr(hdu->header, PS_LIST_TAIL, "HISTORY", PS_META_DUPLICATE_OK, comment, "");
     398            psFree(comment);
     399
     400            // write metadata header value
     401            psMetadataAddF32(hdu->header, PS_LIST_TAIL, "OVER_VAL", PS_META_REPLACE, "Overscan mean", vectorStats->sampleMean);
     402            psMetadataAddF32(hdu->header, PS_LIST_TAIL, "OVER_SIG", PS_META_REPLACE, "Overscan stdev", vectorStats->sampleStdev);
     403
     404            // EAM 2022.03.29 : if the calculated overscan value is below the threshold,
     405            // declare the readout dead and mask
     406         
     407            if ((vectorStats->sampleMean < overscanOpts->minValid) || (vectorStats->sampleMean > overscanOpts->maxValid)) {
     408                fprintf (stderr, "bad overscan (2) %f, masking readout\n", vectorStats->sampleMean);
     409                psImage *mask = input->mask;
     410                for (int y = 0; y < mask->numRows; y++) {
     411                    for (int x = 0; x < mask->numCols; x++) {
     412                        mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] |= overscanOpts->maskVal;
     413                    }
     414                }
     415            }
     416
     417            psFree (vectorStats);
    387418        }
    388419
     
    469500          psMetadataAddF32(hdu->header, PS_LIST_TAIL, "OVER_VAL", PS_META_REPLACE, "Overscan mean", vectorStats->sampleMean);
    470501          psMetadataAddF32(hdu->header, PS_LIST_TAIL, "OVER_SIG", PS_META_REPLACE, "Overscan stdev", vectorStats->sampleStdev);
     502
     503          // EAM 2022.03.29 : if the calculated overscan value is below the threshold,
     504          // declare the readout dead and mask
     505         
     506          if ((vectorStats->sampleMean < overscanOpts->minValid) || (vectorStats->sampleMean > overscanOpts->maxValid)) {
     507              fprintf (stderr, "bad overscan (3) %f, masking readout\n", vectorStats->sampleMean);
     508              psImage *mask = input->mask;
     509              for (int y = 0; y < mask->numRows; y++) {
     510                  for (int x = 0; x < mask->numCols; x++) {
     511                      mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] |= overscanOpts->maskVal;
     512                  }
     513              }
     514          }
    471515          psFree (vectorStats);
    472516        }
  • trunk/psModules/src/detrend/pmOverscan.h

    r14505 r42379  
    4343    int boxcar;                         ///< Boxcar smoothing radius
    4444    float gauss;                        ///< Gaussian smoothing sigma
     45    float minValid;                     ///< if overscan is too low, readout is dead : mask
     46    float maxValid;                     ///< if overscan is too high, readout is dead : mask
     47    psImageMaskType maskVal;            ///< Mask value to give dead readouts
     48
    4549    // Outputs
    4650    psPolynomial1D *poly;               ///< Result of polynomial fit
  • trunk/psModules/src/detrend/pmPattern.c

    r42092 r42379  
    10051005    psFree(meanMask);
    10061006
     1007    return true;
     1008}
     1009
     1010// Compare the backs (cellBackgrounds) vector to each of the patterns loaded for this chip.
     1011// Choose the one that matches best & mask as appropriate
     1012// can we pass the backgrounds in using an image (8 x 8)
     1013bool pmPatternDeadCells(pmChip *chip, const psVector *backs, psImageMaskType maskVal)
     1014{
     1015    PS_ASSERT_PTR_NON_NULL(chip, false);
     1016    PS_ASSERT_VECTOR_NON_NULL(backs, false);
     1017    PS_ASSERT_VECTOR_SIZE(backs, chip->cells->n, false);
     1018    PS_ASSERT_VECTOR_TYPE(backs, PS_TYPE_F32, false);
     1019
     1020    // Look for the dead cell pattern cube in the analysis metadata.
     1021    // NOTE: not all chips have the pattern, skip if not found.
     1022    bool mdok;
     1023    psImage *deadCellPattern = (psImage *) psMetadataLookupPtr (&mdok, chip->analysis, "PTN.DEAD.CELL");
     1024    if (!mdok) {
     1025        psLogMsg("psModules.detrend", PS_LOG_DETAIL, "No DEAD CELL pattern for chip, skipping\n");
     1026        return true;
     1027    }
     1028
     1029    int numCells = backs->n;            // Number of cells
     1030    int numColsD = deadCellPattern->numCols;
     1031    int numRowsD = deadCellPattern->numRows;
     1032
     1033    assert (backs->n == numRowsD);
     1034
     1035    // The background values need to be normalized (divide by the median).
     1036    // First extract the valid data values
     1037    psVector *valid = psVectorAllocEmpty(backs->n, PS_TYPE_F32); // Mean for each cell
     1038    for (int i = 0; i < backs->n; i++) {
     1039        float value = backs->data.F32[i];
     1040        if (!isfinite(value)) { backs->data.F32[i] = NAN; continue; }
     1041        if (value > 50000.0)  { backs->data.F32[i] = NAN; continue; } // XXX warning: hard-wired value
     1042        psVectorAppend (valid, value);
     1043    }
     1044    if (valid->n == 0) {
     1045        psLogMsg("psModules.detrend", PS_LOG_DETAIL, "No valid backgrounds, skipping\n");
     1046        psFree (valid);
     1047        return true;
     1048    }
     1049
     1050    // Second, calculate the median
     1051    psVectorSortInPlace (valid);
     1052    int midPt = valid->n / 2.0;
     1053    float median = valid->n % 2 ? valid->data.F32[midPt] : 0.5*(valid->data.F32[midPt] + valid->data.F32[midPt-1]);
     1054    psFree (valid);
     1055
     1056    // Finally, renormalize:
     1057    for (int i = 0; i < backs->n; i++) {
     1058        if (!isfinite(backs->data.F32[i])) { continue; }
     1059        backs->data.F32[i] /= median;
     1060    }
     1061
     1062    // there are 2 columns (value & mask) for each mode, plus the constant mode
     1063    int nModes = numColsD / 2 + 1;
     1064   
     1065    psVector *stdev = psVectorAlloc(nModes, PS_TYPE_F32); // Mean for each cell
     1066
     1067    // measure stdev for each comparison
     1068    for (int i = 0; i < nModes; i++) {
     1069        float Sum1 = 0.0;
     1070        float Sum2 = 0.0;
     1071        int   Npts = 0;
     1072
     1073        // choose the column with the background values for this mode
     1074        int nModeColumn = 2*(i - 1);
     1075
     1076        for (int j = 0; j < backs->n; j++) {
     1077
     1078            float valObs = backs->data.F32[j];
     1079            float valRef = (i == 0) ? 0.0 : deadCellPattern->data.F32[j][nModeColumn];
     1080
     1081            if (!isfinite(valObs)) continue;
     1082            if (!isfinite(valRef)) continue;
     1083
     1084            float dS = valObs - valRef;
     1085            Sum1 += dS;
     1086            Sum2 += dS*dS;
     1087            Npts ++;
     1088        }
     1089        if (Npts == 0) {
     1090            // is this is an error?
     1091            // no valid data, ignore this test
     1092            psLogMsg("psModules.detrend", PS_LOG_DETAIL, "No valid backgrounds, skipping\n");
     1093            psFree (stdev);
     1094            return true;
     1095        }
     1096
     1097        float mean = Sum1 / Npts;
     1098        float sigma = sqrt(Sum2 / Npts - mean*mean);
     1099        stdev->data.F32[i] = sigma;
     1100        fprintf (stderr, "mode: %d, stdev: %f\n", i, sigma);
     1101    }
     1102
     1103    // loop over stdev and choose the lowest one
     1104    int   minI = 0;
     1105    float minV = stdev->data.F32[minI];
     1106
     1107    for (int i = 1; i < nModes; i++) {
     1108        if (stdev->data.F32[i] < minV) {
     1109            minI = i;
     1110            minV = stdev->data.F32[i];
     1111        }
     1112    }
     1113    psFree (stdev);
     1114
     1115    if (minI == 0) return true;
     1116
     1117    int nModeColumnMask = 2*(minI - 1) + 1;
     1118
     1119    // now mask bad cells
     1120    for (int i = 0; i < numCells; i++) {
     1121        if (deadCellPattern->data.F32[i][nModeColumnMask] > 0) continue;
     1122
     1123        pmCell *cell = chip->cells->data[i]; // Cell of interest
     1124        pmReadout *ro = cell->readouts->data[0]; // Readout of interest
     1125
     1126        psImage *mask = ro->mask; // mask of interest
     1127        int numCols = mask->numCols, numRows = mask->numRows; // Size of image
     1128       
     1129        for (int y = 0; y < numRows; y++) {
     1130            for (int x = 0; x < numCols; x++) {
     1131                mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] |= maskVal;
     1132            }
     1133        }
     1134    }
    10071135    return true;
    10081136}
  • trunk/psModules/src/detrend/pmPattern.h

    r35081 r42379  
    8686
    8787
     88bool pmPatternDeadCells(pmChip *chip, const psVector *backs, psImageMaskType maskVal);
     89
    8890/// @}
    8991#endif
  • trunk/psModules/src/detrend/pmPatternIO.c

    r41892 r42379  
    482482}
    483483
    484 // read the set of tables, one for each chip
     484// Read the set of tables, one for each chip.  The values are saved on the cell->analysis
     485// metadata of the pmFPAfile associated with the pattern file.  Later, when this is used (e.g.,
     486// ppImageDetrendPatternRowApply), the values are transferred to the cell->analysis metadata of
     487// the pmFPAfile for the image being processed.
    485488bool pmPatternRowAmpReadChips (pmFPAfile *file) {
    486489
     
    560563    return true;
    561564}
     565
     566/**************** PatternDeadCells I/O *************************/
     567
     568bool pmPatternDeadCellsRead (const pmFPAview *view, pmFPAfile *file, const pmConfig *config)
     569    {
     570        // read the full model in one pass: require the level to be FPA
     571        if (view->chip != -1) {
     572            psError(PS_ERR_IO, false, "Pattern Dead Cells must be read at the FPA level");
     573            return false;
     574        }
     575
     576        if (!pmPatternDeadCellsReadFPA (file)) {
     577            psError(PS_ERR_IO, false, "Failed to read Pattern Dead Cells for fpa");
     578            return false;
     579        }
     580        return true;
     581    }
     582
     583// read in all chip-level Pattern Dead Cells data for this FPA
     584bool pmPatternDeadCellsReadFPA (pmFPAfile *file) {
     585
     586    if (!pmPatternDeadCellsReadChips (file)) {
     587        psError(PS_ERR_IO, false, "Failed to read Pattern Dead Cells for chips");
     588        return false;
     589    }
     590
     591    return true;
     592}
     593
     594// Read the set of dead cell image cubes, one for each chip.  The values are saved on the
     595// chip->analysis metadata of the pmFPAfile associated with the pattern file.  Later, when this
     596// is used (e.g., ppImageDetrendPatternDeadCellsApply), the values are transferred to the
     597// chip->analysis metadata of the pmFPAfile for the image being processed.
     598bool pmPatternDeadCellsReadChips (pmFPAfile *file) {
     599
     600    bool haveData, status;
     601
     602    // loop over the extensions
     603    // for each extension, use the extname (eg, XY01.ded) to assign to a chip
     604
     605    // move to the start of the file
     606    haveData = psFitsMoveExtNum (file->fits, 1, false);
     607    if (!haveData) {
     608        psError(PS_ERR_IO, false, "Failed to read even the first extension?");
     609        return false;
     610    }
     611
     612    int nGood = 0;
     613    while (haveData) {
     614
     615        // load the header
     616        psMetadata *header = psFitsReadHeader(NULL, file->fits); // The FITS header
     617        if (!header) psAbort("cannot read dead cell header");
     618
     619        // load the full model in one shot
     620        psImage *deadCellData = psFitsReadImage(file->fits, psRegionSet(0,0,0,0), 0); // dead cell patterns
     621        if (!deadCellData) psAbort("cannot read dead cell pattern");
     622       
     623        // determine the chip (not all chips have DEAD CELL patterns)
     624        char *extname = psMetadataLookupStr (&status, header, "EXTNAME");
     625        psLogMsg ("psModules.detrend", 8, "read dead cell pattern for extname %s\n", extname);
     626
     627        // I expect to find a name of the form: chipName.ded (eg, XY01.ded)
     628        // where chipName like 'XY01'
     629        psAssert (strlen(extname) == 8, "invalid extension %s", extname);
     630        psAssert (extname[5] == 'd', "invalid extension %s", extname);
     631        psAssert (extname[6] == 'e', "invalid extension %s", extname);
     632        psAssert (extname[7] == 'd', "invalid extension %s", extname);
     633
     634        char chipName[5];
     635        strncpy (chipName, extname, 4);
     636        chipName[4] = 0;
     637
     638        pmChip *chip = pmConceptsChipFromName (file->fpa, chipName);
     639        if (!chip) psAbort ("invalid chip?");
     640
     641        psMetadataAddImage (chip->analysis, PS_LIST_TAIL, "PTN.DEAD.CELL", PS_META_REPLACE, "", deadCellData);
     642        psFree (deadCellData);
     643        psFree (header);
     644
     645        // move to the next extension
     646        haveData = psFitsMoveExtNum (file->fits, 1, true);
     647        nGood ++;
     648    }
     649    psLogMsg ("psModules.detrend", 4, "read patterns for %d chips from Pattern Dead Cells file\n", nGood);
     650
     651    return true;
     652}
  • trunk/psModules/src/detrend/pmPatternIO.h

    r41892 r42379  
    4040bool pmPatternRowAmpReadChips (pmFPAfile *file);
    4141
     42bool pmPatternDeadCellsRead (const pmFPAview *view, pmFPAfile *file, const pmConfig *config);
     43bool pmPatternDeadCellsReadFPA (pmFPAfile *file);
     44bool pmPatternDeadCellsReadChips (pmFPAfile *file);
     45
    4246#endif
Note: See TracChangeset for help on using the changeset viewer.