- Timestamp:
- Mar 10, 2006, 5:20:10 PM (20 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/rel10_ifa/psModules/src/astrom/pmConceptsStandard.c
r6552 r6570 16 16 17 17 18 // Read FPA.RA and translate 19 psMetadataItem *pmConceptRead_FPA_RA(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db) 20 { 21 double ra = NAN; // The Right Ascension 22 psMetadataItem *raItem = pmConceptRead(fpa, NULL, NULL, db, "FPA.RA"); // The FPA.RA item 23 if (raItem) { 24 switch (raItem->type) { 25 case PS_TYPE_F32: 26 ra = raItem->data.F32; 27 break; 28 case PS_TYPE_F64: 29 ra = raItem->data.F64; 30 break; 31 case PS_DATA_STRING: 32 // Sexagesimal format 18 static double defaultCoordScaling(psMetadataItem *pattern) 19 { 20 if (strcmp(pattern->name, "FPA.RA") == 0) { 21 psLogMsg(__func__, PS_LOG_WARN, "Assuming format for %s is HOURS.\n", pattern->name); 22 return M_PI / 12.0; 23 } else if (strcmp(pattern->name, "FPA.DEC") == 0) { 24 psLogMsg(__func__, PS_LOG_WARN, "Assuming format for %s is DEGREES.\n", pattern->name); 25 return M_PI / 180.0; 26 } else { 27 psAbort("Should never ever get here.\n"); 28 } 29 } 30 31 32 // FPA.RA and FPA.DEC 33 psMetadataItem *pmConceptParse_FPA_Coords(psMetadataItem *concept, psMetadataItem *pattern, psMetadata *cameraFormat, pmFPA *fpa, pmChip *chip, pmCell *cell) 34 { 35 assert(concept); 36 assert(pattern); 37 assert(cameraFormat); 38 39 double coords = NAN; // The coordinates 40 switch (concept->type) { 41 case PS_TYPE_F32: 42 coords = concept->data.F32; 43 break; 44 case PS_TYPE_F64: 45 coords = concept->data.F64; 46 break; 47 case PS_DATA_STRING: 48 // Sexagesimal format 49 { 50 int big, medium; 51 float small; 52 // XXX: Upgrade path is to allow dd:mm.mmm 53 if (sscanf(concept->data.V, "%d:%d:%f", &big, &medium, &small) != 3 && 54 sscanf(concept->data.V, "%d %d %f", &big, &medium, &small) != 3) 33 55 { 34 int big, medium; 35 float small; 36 // XXX: Upgrade path is to allow dd:mm.mmm 37 if (sscanf(raItem->data.V, "%d:%d:%f", &big, &medium, &small) != 3 && 38 sscanf(raItem->data.V, "%d %d %f", &big, &medium, &small) != 3) 39 { 40 psError(PS_ERR_IO, true, "Cannot interpret FPA.RA: %s\n", raItem->data.V); 41 break; 42 } 43 ra = abs(big) + (float)medium/60.0 + small/3600.0; 44 if (big < 0) 45 { 46 ra *= -1.0; 47 } 48 } 49 break; 50 default: 51 psError(PS_ERR_IO, true, "FPA.RA is of an unexpected type: %x\n", raItem->type); 52 } 53 54 // How to interpret the RA 55 const psMetadata *camera = fpa->camera; // Camera configuration data 56 bool mdok = true; // Status of MD lookup 57 psMetadata *formats = psMetadataLookupMD(&mdok, camera, "FORMATS"); 58 if (mdok && formats) { 59 psString raFormat = psMetadataLookupStr(&mdok, formats, "FPA.RA"); 60 if (mdok && strlen(raFormat) > 0) { 61 if (strcasecmp(raFormat, "HOURS") == 0) { 62 ra *= M_PI / 12.0; 63 } else if (strcasecmp(raFormat, "DEGREES") == 0) { 64 ra *= M_PI / 180.0; 65 } else if (strcasecmp(raFormat, "RADIANS") == 0) { 66 // No action required 67 } else { 68 psLogMsg(__func__, PS_LOG_WARN, "Don't understand FPA.RA in FORMATS (%s) --- assuming" 69 " HOURS.\n"); 70 ra *= M_PI / 12.0; 71 } 72 } else { 73 psError(PS_ERR_IO, false, "Unable to find FPA.RA in FORMATS --- assuming HOURS.\n"); 74 ra *= M_PI / 12.0; 75 } 76 } else { 77 psError(PS_ERR_IO, false, "Unable to find FORMAT metadata in camera configuration --- " 78 "assuming format for FPA.RA is HOURS.\n"); 79 ra *= M_PI / 12.0; 80 } 81 } else { 82 psError(PS_ERR_IO, false, "Couldn't find FPA.RA.\n"); 83 } 84 85 return psMetadataItemAllocF64("FPA.RA", "Right Ascension of boresight", ra); 86 } 87 88 // Read FPA.DEC and translate 89 psMetadataItem *pmConceptRead_FPA_DEC(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db) 90 { 91 double dec = NAN; // The DEC 92 psMetadataItem *decItem = pmConceptRead(fpa, NULL, NULL, db, "FPA.DEC"); // The FPA.DEC item 93 if (decItem) { 94 switch (decItem->type) { 95 case PS_TYPE_F32: 96 dec = decItem->data.F32; 97 break; 98 case PS_TYPE_F64: 99 dec = decItem->data.F64; 100 break; 101 case PS_DATA_STRING: 102 // Sexagesimal format 56 psError(PS_ERR_IO, true, "Cannot interpret FPA.RA: %s\n", concept->data.V); 57 break; 58 } 59 coords = abs(big) + (float)medium/60.0 + small/3600.0; 60 if (big < 0) 103 61 { 104 int big, medium; 105 float small; 106 // XXX: Upgrade path is to allow dd:mm.mmm 107 if (sscanf(decItem->data.V, "%d:%d:%f", &big, &medium, &small) != 3 && 108 sscanf(decItem->data.V, "%d %d %f", &big, &medium, &small) != 3) 109 { 110 psError(PS_ERR_IO, true, "Cannot interpret FPA.DEC: %s\n", decItem->data.V); 111 break; 112 } 113 dec = abs(big) + (float)medium/60.0 + small/3600.0; 114 if (big < 0) 115 { 116 dec *= -1.0; 117 } 118 } 119 break; 120 default: 121 psError(PS_ERR_IO, true, "FPA.DEC is of an unexpected type: %x\n", decItem->type); 122 } 123 124 // How to interpret the DEC 125 const psMetadata *camera = fpa->camera; // Camera configuration data 126 bool mdok = true; // Status of MD lookup 127 psMetadata *formats = psMetadataLookupMD(&mdok, camera, "FORMATS"); 128 if (mdok && formats) { 129 psString decFormat = psMetadataLookupStr(&mdok, formats, "FPA.DEC"); 130 if (mdok && strlen(decFormat) > 0) { 131 if (strcasecmp(decFormat, "HOURS") == 0) { 132 dec *= M_PI / 12.0; 133 } else if (strcasecmp(decFormat, "DEGREES") == 0) { 134 dec *= M_PI / 180.0; 135 } else if (strcasecmp(decFormat, "RADIANS") == 0) { 136 // No action required 137 } else { 138 psLogMsg(__func__, PS_LOG_WARN, "Don't understand FPA.DEC in FORMATS (%s) --- " 139 "assuming DEGREES.\n"); 140 dec *= M_PI / 180.0; 141 } 142 } else { 143 psError(PS_ERR_IO, false, "Unable to find FPA.DEC in FORMATS --- assuming DEGREES.\n"); 144 dec *= M_PI / 180.0; 145 } 146 } else { 147 psError(PS_ERR_IO, false, "Unable to find FORMATS metadata in camera configuration --- " 148 "assuming format for FPA.DEC is DEGREES.\n"); 149 dec *= M_PI / 180.0; 150 } 151 } else { 152 psError(PS_ERR_IO, false, "Couldn't find FPA.DEC.\n"); 153 } 154 155 return psMetadataItemAllocF64("FPA.DEC", "Declination of boresight", dec); 156 } 157 158 159 bool pmConceptWrite_FPA_RA(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db) 160 { 161 double ra = psMetadataLookupF64(NULL, fpa->concepts, "FPA.RA"); // The RA 162 163 // How to interpret the RA 164 const psMetadata *camera = fpa->camera; // Camera configuration data 165 bool mdok = true; // Status of MD lookup 166 psMetadata *formats = psMetadataLookupMD(&mdok, camera, "FORMATS"); 62 coords *= -1.0; 63 } 64 } 65 break; 66 default: 67 psError(PS_ERR_IO, true, "%s concept is of an unexpected type: %x\n", pattern->name, concept->type); 68 return NULL; 69 } 70 71 // How to interpret the coordinates 72 bool mdok = true; // Status of MD lookup 73 psMetadata *formats = psMetadataLookupMD(&mdok, cameraFormat, "FORMATS"); 167 74 if (mdok && formats) { 168 psString raFormat = psMetadataLookupStr(&mdok, formats, "FPA.RA");169 if (mdok && strlen( raFormat) > 0) {170 if (strcasecmp( raFormat, "HOURS") == 0) {171 ra /= M_PI / 12.0;172 } else if (strcasecmp( raFormat, "DEGREES") == 0) {173 ra /= M_PI / 180.0;174 } else if (strcasecmp( raFormat, "RADIANS") == 0) {75 psString format = psMetadataLookupStr(&mdok, formats, blank->name); 76 if (mdok && strlen(format) > 0) { 77 if (strcasecmp(format, "HOURS") == 0) { 78 coords *= M_PI / 12.0; 79 } else if (strcasecmp(format, "DEGREES") == 0) { 80 coords *= M_PI / 180.0; 81 } else if (strcasecmp(format, "RADIANS") == 0) { 175 82 // No action required 176 83 } else { 177 psLogMsg(__func__, PS_LOG_WARN, "Don't understand FPA.RA in FORMATS (%s) --- assuming" 178 " HOURS.\n"); 179 ra /= M_PI / 12.0; 84 coords *= defaultCoordScaling(pattern); 180 85 } 181 86 } else { 182 psError(PS_ERR_IO, false, "Unable to find FPA.RA in FORMATS --- assuming HOURS.\n"); 183 ra /= M_PI / 12.0; 87 coords *= defaultCoordScaling(pattern); 184 88 } 185 89 } else { 186 psError(PS_ERR_IO, false, "Unable to find FORMAT metadata in camera configuration --- " 187 "assuming format for FPA.RA is HOURS.\n"); 188 ra /= M_PI / 12.0; 90 coords *= defaultCoordScaling(pattern); 91 } 92 93 return psMetadataItemAllocF64(pattern->name, pattern->comment, coords); 94 } 95 96 // FPA.RA and FPA.DEC 97 psMetadataItem *pmConceptFormat_FPA_Coords(psMetadataItem *concept, psMetadataItem *pattern, pmConceptSpec *spec, psMetadata *cameraFormat) 98 { 99 assert(concept); 100 assert(pattern); 101 assert(cameraFormat); 102 103 double coords = concept->data.F64; // The coordinates 104 105 // How to interpret the coordinates 106 bool mdok = true; // Status of MD lookup 107 psMetadata *formats = psMetadataLookupMD(&mdok, cameraFormat, "FORMATS"); 108 if (mdok && formats) { 109 psString format = psMetadataLookupStr(&mdok, formats, pattern->name); 110 if (mdok && strlen(format) > 0) { 111 if (strcasecmp(format, "HOURS") == 0) { 112 coords /= M_PI / 12.0; 113 } else if (strcasecmp(format, "DEGREES") == 0) { 114 coords /= M_PI / 180.0; 115 } else if (strcasecmp(format, "RADIANS") == 0) { 116 // No action required 117 } else { 118 coords /= defaultCoordScaling(pattern); 119 } 120 } else { 121 coords /= defaultCoordScaling(pattern); 122 } 123 } else { 124 coords /= defaultCoordScaling(pattern); 189 125 } 190 126 … … 193 129 float small; 194 130 big = (int)ra; 195 medium = (int)(60.0*(ra - (double)big)); 196 small = 3600.0*(ra - (double)big - 60.0 * (double)medium); 197 psString raString = psStringCopy(""); 198 psStringAppend(&raString, "%d:%d:%.2f", big, medium, small); 199 psMetadataItem *raItem = psMetadataItemAllocStr("FPA.RA", "Right Ascension of the boresight", 200 raString); 201 pmConceptWriteItem(fpa, NULL, NULL, db, raItem); 202 psFree(raItem); 203 psFree(raString); 204 205 return true; 206 } 207 208 bool pmConceptWrite_FPA_DEC(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db) 209 { 210 double dec = psMetadataLookupF64(NULL, fpa->concepts, "FPA.DEC"); // The DEC 211 212 // How to interpret the DEC 213 const psMetadata *camera = fpa->camera; // Camera configuration data 214 bool mdok = true; // Status of MD lookup 215 psMetadata *formats = psMetadataLookupMD(&mdok, camera, "FORMATS"); 216 if (mdok && formats) { 217 psString decFormat = psMetadataLookupStr(&mdok, formats, "FPA.DEC"); 218 if (mdok && strlen(decFormat) > 0) { 219 if (strcasecmp(decFormat, "HOURS") == 0) { 220 dec /= M_PI / 12.0; 221 } else if (strcasecmp(decFormat, "DEGREES") == 0) { 222 dec /= M_PI / 180.0; 223 } else if (strcasecmp(decFormat, "RADIANS") == 0) { 224 // No action required 225 } else { 226 psLogMsg(__func__, PS_LOG_WARN, "Don't understand FPA.DEC in FORMATS (%s) --- assuming" 227 " DEGREES.\n"); 228 dec /= M_PI / 180.0; 229 } 230 } else { 231 psError(PS_ERR_IO, false, "Unable to find FPA.DEC in FORMATS --- assuming DEGREES.\n"); 232 dec /= M_PI / 180.0; 233 } 234 } else { 235 psError(PS_ERR_IO, false, "Unable to find FORMAT metadata in camera configuration --- " 236 "assuming format for FPA.DEC is HOURS.\n"); 237 dec /= M_PI / 12.0; 238 } 239 240 // We choose to write sexagesimal format 241 int big, medium; 242 float small; 243 big = (int)dec; 244 medium = (int)(60.0*(dec - (double)big)); 245 small = 3600.0*(dec - (double)big - 60.0 * (double)medium); 246 psString decString = psStringCopy(""); 247 psStringAppend(&decString, "%d:%d:%.2f", big, medium, small); 248 psMetadataItem *decItem = psMetadataItemAllocStr("FPA.DEC", "Right Ascension of the boresight", 249 decString); 250 pmConceptWriteItem(fpa, NULL, NULL, db, decItem); 251 psFree(decItem); 252 psFree(decString); 253 254 return true; 255 } 256 257 258 psMetadataItem *pmConceptRead_CELL_TRIMSEC(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db) 259 { 131 medium = (int)(60.0*(coords - (double)big)); 132 small = 3600.0*(coords - (double)big - 60.0 * (double)medium); 133 psString coordString = NULL; // String with the coordinates in sexagesimal format 134 psStringAppend(&coordString, "%d:%d:%.2f", big, medium, small); 135 psMetadataItem *coordItem = psMetadataItemAllocStr(pattern->name, pattern->comment, coordString); 136 psFree(coordString); 137 138 return coordItem; 139 } 140 141 142 psMetadataItem *pmConceptParse_CELL_TRIMSEC(psMetadataItem *concept, psMetadataItem *pattern, psMetadata *cameraFormat, pmFPA *fpa, pmChip *chip, pmCell *cell) 143 { 144 assert(concept); 145 assert(cell); 146 assert(pattern); 147 148 psMetadata *cellConfig = cell->config; // The cell configuration 260 149 psRegion *trimsec = psAlloc(sizeof(psRegion)); // Make space for a psRegion (usually passed by value) 261 150 262 psMetadataItem *secItem = pmConceptRead(fpa, chip, cell, db, "CELL.TRIMSEC"); 263 if (! secItem) { 264 psError(PS_ERR_IO, false, "Couldn't find CELL.TRIMSEC.\n"); 265 *trimsec = psRegionSet(0.0, 0.0, 0.0, 0.0); 266 } else if (secItem->type != PS_DATA_STRING) { 267 psError(PS_ERR_IO, true, "CELL.TRIMSEC is not of type STR (%x)\n", secItem->type); 151 if (concept->type != PS_DATA_STRING) { 152 psError(PS_ERR_IO, true, "CELL.TRIMSEC after read is not of type STR (%x)\n", concept->type); 268 153 *trimsec = psRegionSet(0.0, 0.0, 0.0, 0.0); 269 154 } else { 270 psString section = secItem->data.V; // The section string 271 272 psMetadataItem *sourceItem = pmConceptRead(fpa, chip, cell, db, "CELL.TRIMSEC.SOURCE"); 273 if (! sourceItem) { 274 psError(PS_ERR_IO, false, "Couldn't find CELL.TRIMSEC.SOURCE.\n"); 275 *trimsec = psRegionSet(0.0, 0.0, 0.0, 0.0); 276 } else if (sourceItem->type != PS_DATA_STRING) { 277 psError(PS_ERR_IO, true, "CELL.TRIMSEC.SOURCE is not of type STR (%x)\n", sourceItem->type); 278 *trimsec = psRegionSet(0.0, 0.0, 0.0, 0.0); 279 } else { 280 psString source = sourceItem->data.V; // The source string 281 282 if (strcasecmp(source, "VALUE") == 0) { 283 *trimsec = psRegionFromString(section); 284 } else if (strcasecmp(source, "HEADER") == 0) { 285 psMetadata *header = NULL; // The FITS header 286 if (cell->hdu) { 287 header = cell->hdu->header; 288 } else if (chip->hdu) { 289 header = chip->hdu->header; 290 } else if (fpa->hdu) { 291 header = fpa->hdu->header; 292 } 293 if (! header) { 294 psError(PS_ERR_IO, true, "Unable to find FITS header!\n"); 295 *trimsec = psRegionSet(0.0, 0.0, 0.0, 0.0); 296 } else { 297 bool mdok = true; // Status of MD lookup 298 psString secValue = psMetadataLookupStr(&mdok, header, section); 299 if (! mdok || ! secValue) { 300 psError(PS_ERR_IO, false, "Unable to locate header %s\n", section); 301 *trimsec = psRegionSet(0.0, 0.0, 0.0, 0.0); 302 } else { 303 *trimsec = psRegionFromString(secValue); 304 } 305 } 306 } else { 307 psError(PS_ERR_IO, true, "CELL.TRIMSEC.SOURCE (%s) is not HEADER or VALUE --- trying " 308 "VALUE.\n", source); 309 *trimsec = psRegionFromString(section); 310 } // Value of CELL.TRIMSEC.SOURCE 311 } // Looking up CELL.TRIMSEC.SOURCE 312 } // Looking up CELL.TRIMSEC 313 314 psMetadataItem *item = psMetadataItemAllocPtr("CELL.TRIMSEC", PS_DATA_UNKNOWN, "Trim section", trimsec); 155 *trimsec = psRegionFromString(concept->data.V); 156 } 157 158 psMetadataItem *item = psMetadataItemAllocPtr(pattern->name, PS_DATA_UNKNOWN, pattern->comment, trimsec); 315 159 psFree(trimsec); 316 160 return item; 317 161 } 318 162 319 320 psMetadataItem *pmConceptRead_CELL_BIASSEC(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db) 321 { 163 psMetadataItem *pmConceptParse_CELL_BIASSEC(psMetadataItem *concept, psMetadataItem *pattern, psMetadata *cameraFormat, pmFPA *fpa, pmChip *chip, pmCell *cell) 164 { 165 assert(concept); 166 assert(cell); 167 assert(pattern); 168 psMetadata *cellConfig = cell->config; // The cell configuration 169 322 170 psList *biassecs = psListAlloc(NULL); // List of bias sections 323 171 psMetadataItem *item = psMetadataItemAlloc("CELL.BIASSEC", PS_DATA_LIST, "Bias sections", biassecs); 324 172 psFree(biassecs); // Drop reference 325 173 326 psMetadataItem *secItem = pmConceptRead(fpa, chip, cell, db, "CELL.BIASSEC"); 327 if (! secItem) { 328 psError(PS_ERR_IO, false, "Couldn't find CELL.BIASSEC.\n"); 329 return item; 330 } 331 if (secItem->type != PS_DATA_STRING) { 332 psError(PS_ERR_IO, true, "CELL.BIASSEC is not of type STR (%x)\n", secItem->type); 333 return item; 334 } 335 336 psString sections = secItem->data.V; // The section string 337 338 psMetadataItem *sourceItem = pmConceptRead(fpa, chip, cell, db, "CELL.BIASSEC.SOURCE"); 339 if (! sourceItem) { 340 psError(PS_ERR_IO, false, "Couldn't find CELL.BIASSEC.SOURCE.\n"); 341 return item; 342 } else if (sourceItem->type != PS_DATA_STRING) { 343 psError(PS_ERR_IO, true, "CELL.BIASSEC.SOURCE is not of type STR (%x)\n", sourceItem->type); 344 return item; 345 } 346 347 psString source = sourceItem->data.V; // The source string 348 349 if (! strcasecmp(source, "NONE")) { 350 return item; // There is no biassec 351 } 352 353 psList *secList = psStringSplit(sections, " ;"); // List of sections 354 psListIterator *secIter = psListIteratorAlloc(secList, PS_LIST_HEAD, false); // Iterator over 355 // sections 356 psString aSection = NULL; // A section from the list 357 while ((aSection = psListGetAndIncrement(secIter))) { 358 psRegion *region = psAlloc(sizeof(psRegion)); // Make space for a psRegion (usually passed by 359 // value) 360 361 if (strcasecmp(source, "VALUE") == 0) { 362 *region = psRegionFromString(aSection); 363 } else if (strcasecmp(source, "HEADER") == 0) { 364 psMetadata *header = NULL; // The FITS header 365 if (cell->hdu) { 366 header = cell->hdu->header; 367 } else if (chip->hdu) { 368 header = chip->hdu->header; 369 } else if (fpa->hdu) { 370 header = fpa->hdu->header; 371 } 372 if (! header) { 373 psError(PS_ERR_IO, true, "Unable to find FITS header!\n"); 374 *region = psRegionSet(0.0,0.0,0.0,0.0); 174 switch (concept->type) { 175 case PS_DATA_STRING: { 176 psList *regions = psStringSplit(concept->data.V, " ;"); // List of regions 177 psListIterator *regionsIter = psListIteratorAlloc(regions, PS_LIST_HEAD, false); // Iterator 178 psString regionString = NULL; // Region string from iteration 179 while ((regionString = psListGetAndIncrement(regionsIter))) { 180 psRegion *region = psAlloc(sizeof(psRegion)); // The region 181 *region = psRegionFromString(regionString); 182 psListAdd(biassecs, PS_LIST_TAIL, region); 183 psFree(region); // Drop reference 184 } 185 psFree(regionsIter); 186 psFree(regions); 187 break; 188 } 189 case PS_DATA_LIST: { 190 psList *regions = concept->data.V; // The list of regions 191 psListIterator *regionsIter = psListIteratorAlloc(regions, PS_LIST_HEAD, false); // Iterator 192 psMetadataItem *regionItem = NULL; // Item from list iteration 193 while ((regionItem = psListGetAndIncrement(regionsIter))) { 194 if (regionItem->type != PS_DATA_STRING) { 195 psLogMsg(__func__, PS_LOG_WARN, "CELL.BIASSEC member is not of type STR --- ignored.\n"); 196 continue; 197 } 198 psRegion *region = psAlloc(sizeof(psRegion)); // The region 199 *region = psRegionFromString(regionItem->data.V); 200 psListAdd(biassecs, PS_LIST_TAIL, region); 201 psFree(region); // Drop reference 202 } 203 psFree(regionsIter); 204 break; 205 } 206 default: 207 psError(PS_ERR_IO, true, "CELL.BIASSEC after read is not of type STRING or LIST --- assuming " 208 "blank.\n"); 209 } 210 211 psMetadataItem *item = psMetadataItemAllocPtr(pattern->name, PS_DATA_LIST, pattern->comment, biassecs); 212 psFree(biassecs); 213 return item; 214 } 215 216 // CELL.XBIN and CELL.YBIN 217 psMetadataItem *pmConceptParse_CELL_BINNING(psMetadataItem *concept, psMetadataItem *pattern, psMetadata *cameraFormat, pmFPA *fpa, pmChip *chip, pmCell *cell) 218 { 219 assert(concept); 220 assert(pattern); 221 222 int binning = 1; // Binning factor in x 223 if (concept->type == PS_DATA_STRING) { 224 psString binString = concept->data.V; // The string containing the binning 225 if ((strcmp(pattern->name, "CELL.XBIN") == 0 && sscanf(binString, "%d %*d", &binning) != 1 && 226 sscanf(binString, "%d,%*d", &binning) != 1) || 227 (strcmp(pattern->name, "CELL.YBIN") == 0 && sscanf(binString, "%*d %d", &binning) != 1 && 228 sscanf(binString, "%*d,%d", &binning) != 1) { 229 psError(PS_ERR_IO, true, "Unable to parse string to get %s: %s\n", pattern->name, binString) 230 ; 231 } 232 } else if (concept->type == PS_TYPE_S32) { 233 binning = concept->data.S32; 375 234 } else { 376 bool mdok = true; // Status of MD lookup 377 psString secValue = psMetadataLookupStr(&mdok, header, aSection); 378 if (! mdok || ! secValue) { 379 psError(PS_ERR_IO, false, "Unable to locate header %s\n", aSection); 380 *region = psRegionSet(0.0,0.0,0.0,0.0); 381 } else { 382 *region = psRegionFromString(secValue); 383 } 384 } 385 } else { 386 psError(PS_ERR_IO, true, "CELL.BIASSEC.SOURCE (%s) is not HEADER or VALUE --- trying " 387 "VALUE.\n", source); 388 *region = psRegionFromString(aSection); 389 } // Value of CELL.BIASSEC.SOURCE 390 391 psListAdd(biassecs, PS_LIST_TAIL, region); 392 psFree(region); 393 } // Iterating over multiple sections 394 psFree(secIter); 395 psFree(secList); 396 397 return item; 398 } 399 400 401 psMetadataItem *pmConceptRead_CELL_XBIN(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db) 402 { 403 int xBin = 1; // Binning factor in x 404 psMetadataItem *binItem = pmConceptRead(fpa, chip, cell, db, "CELL.XBIN"); 405 if (! binItem) { 406 psError(PS_ERR_IO, false, "Couldn't find CELL.XBIN.\n"); 407 } else if (binItem->type == PS_DATA_STRING) { 408 psString binString = binItem->data.V; // The string containing the binning 409 if (sscanf(binString, "%d %*d", &xBin) != 1 && 410 sscanf(binString, "%d,%*d", &xBin) != 1) { 411 psError(PS_ERR_IO, true, "Unable to read string to get x binning: %s\n", binString); 412 } 413 } else if (binItem->type == PS_TYPE_S32) { 414 xBin = binItem->data.S32; 415 } else { 416 psError(PS_ERR_IO, true, "Note sure how to interpret CELL.XBIN of type %x --- assuming 1.\n", 417 binItem->type); 418 } 419 420 return psMetadataItemAllocS32("CELL.XBIN", "Binning in x", xBin); 421 } 422 423 psMetadataItem *pmConceptRead_CELL_YBIN(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db) 424 { 425 int yBin = 1; // Binning factor in y 426 psMetadataItem *binItem = pmConceptRead(fpa, chip, cell, db, "CELL.YBIN"); 427 if (! binItem) { 428 psError(PS_ERR_IO, false, "Couldn't find CELL.YBIN.\n"); 429 } else if (binItem->type == PS_DATA_STRING) { 430 psString binString = binItem->data.V; // The string containing the binning 431 if (sscanf(binString, "%*d %d", &yBin) != 1 && 432 sscanf(binString, "%*d,%d", &yBin) != 1) { 433 psError(PS_ERR_IO, true, "Unable to read string to get y binning: %s\n", binString); 434 } 435 } else if (binItem->type == PS_TYPE_S32) { 436 yBin = binItem->data.S32; 437 } else { 438 psError(PS_ERR_IO, true, "Note sure how to interpret CELL.YBIN of type %x --- assuming 1.\n", 439 binItem->type); 440 } 441 442 return psMetadataItemAllocS32("CELL.YBIN", "Binning in y", yBin); 443 } 444 445 psMetadataItem *pmConceptRead_CELL_TIMESYS(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db) 446 { 235 psError(PS_ERR_IO, true, "Note sure how to parse %s of type %x --- assuming 1.\n", pattern->name, 236 binItem->type); 237 } 238 239 return psMetadataItemAllocS32(pattern->name, pattern->comment, binning); 240 } 241 242 243 psMetadataItem *pmConceptParse_CELL_TIMESYS(psMetadataItem *concept, psMetadataItem *pattern, psMetadata *cameraFormat, pmFPA *fpa, pmChip *chip, pmCell *cell) 244 { 245 assert(concept); 246 assert(pattern); 247 447 248 psTimeType timeSys = PS_TIME_UTC; // The time system 448 psString sys = pmConceptReadString(fpa, chip, cell, db, "CELL.TIMESYS"); // The time system as a string 449 if (! sys || strlen(sys) <= 0) { 249 if (concept->type != PS_DATA_STRING || strlen(sys) <= 0) { 450 250 psError(PS_ERR_IO, true, "Can't interpret CELL.TIMESYS --- assuming UTC.\n"); 451 251 } else if (strcasecmp(sys, "TAI") == 0) { … … 462 262 463 263 psFree(sys); 464 return psMetadataItemAllocS32("CELL.TIMESYS", "Time system", timeSys); 465 } 466 467 468 psMetadataItem *pmConceptRead_CELL_TIME(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db) 469 { 264 return psMetadataItemAllocS32(pattern->name, pattern->comment, timeSys); 265 } 266 267 268 psMetadataItem *pmConceptParse_CELL_TIME(psMetadataItem *concept, psMetadataItem *pattern, psMetadata *cameraFormat, pmFPA *fpa, pmChip *chip, pmCell *cell) 269 { 270 assert(concept); 271 assert(cameraFormat); 272 assert(cell); 273 470 274 // Need CELL.TIMESYS first 471 275 bool mdok = false; // Result of MD lookup … … 475 279 timeSys = PS_TIME_UTC; 476 280 } 281 282 // Get format 283 bool mdok = true; // Status of MD lookup 284 psMetadata *formats = psMetadataLookupMD(&mdok, cameraFormat, "FORMATS"); 285 if (!mdok || !formats) { 286 psError(PS_ERR_IO, false, "Unable to find FORMATS in camera configuration.\n"); 287 return NULL; 288 } 289 290 psString timeFormat = psMetadataLookupStr(&mdok, formats, "CELL.TIME"); 291 if (!mdok || strlen(timeFormat) == 0) { 292 psError(PS_ERR_IO, false, "Unable to find CELL.TIME in FORMATS.\n"); 293 return NULL; 294 } 295 477 296 psTime *time = NULL; // The time 478 479 psMetadataItem *timeItem = pmConceptRead(fpa, chip, cell, db, "CELL.TIME"); 480 if (! timeItem) { 481 psError(PS_ERR_IO, false, "Couldn't find CELL.TIME.\n"); 482 } else { 483 // Get format 484 const psMetadata *camera = fpa->camera; // The camera configuration data 485 bool mdok = true; // Status of MD lookup 486 psMetadata *formats = psMetadataLookupMD(&mdok, camera, "FORMATS"); 487 if (mdok && formats) { 488 psString timeFormat = psMetadataLookupStr(&mdok, formats, "CELL.TIME"); 489 if (mdok && strlen(timeFormat) > 0) { 297 switch (concept->type) { 298 case PS_DATA_LIST: { 299 // The date and time are stored separately 300 // Assume the date is first and the time second 301 psList *dateTime = concept->data.V; // The list containing items for date and time 302 psMetadataItem *dateItem = psListGet(dateTime, PS_LIST_HEAD); // Item containing the date 303 psMetadataItem *timeItem = psListGet(dateTime, PS_LIST_HEAD + 1); // Item containing the time 304 if (dateItem->type != PS_DATA_STRING) { 305 psError(PS_ERR_IO, true, "Date is not of type STR.\n"); 306 return NULL; 307 } 308 psString dateString = dateItem->data.V; // The string with the date 309 int day = 0, month = 0, year = 0; 310 if (sscanf(dateString, "%d-%d-%d", &day, &month, &year) != 3 && 311 sscanf(dateString, "%d/%d/%d", &day, &month, &year) != 3) { 312 psError(PS_ERR_IO, true, "Unable to read date: %s\n", dateString); 313 return NULL; 314 } 315 if (strstr(timeFormat, "BACKWARDS")) { 316 int temp = day; 317 day = year; 318 year = temp; 319 } 320 if (strstr(timeFormat, "PRE2000") || year < 2000) { 321 year += 2000; 322 } 323 324 psString timeString = NULL; // The string with the time 325 if (timeItem->type == PS_DATA_STRING) { 326 timeString = timeItem->data.V; 327 } else { 328 // Assume that time is specified in Second of Day (!) 329 double seconds = NAN; 490 330 switch (timeItem->type) { 491 case PS_DATA_STRING: { 492 psString timeString = timeItem->data.V; // String with the time 493 if (strcasecmp(timeFormat, "ISO") == 0) { 494 // timeString contains an ISO time 495 time = psTimeFromISO(timeString, timeSys); 496 } else if (strcasecmp(timeFormat, "JD") == 0) { 497 double timeValue = strtod (timeString, NULL); 498 time = psTimeFromJD(timeValue); 499 } else if (strcasecmp(timeFormat, "MJD") == 0) { 500 double timeValue = strtod (timeString, NULL); 501 time = psTimeFromMJD(timeValue); 502 } else if (strstr(timeFormat, "SEPARATE")) { 503 // timeString contains headers for the date and time 504 psMetadata *header = NULL; // The FITS header 505 if (cell->hdu) { 506 header = cell->hdu->header; 507 } else if (chip->hdu) { 508 header = chip->hdu->header; 509 } else if (fpa->hdu) { 510 header = fpa->hdu->header; 511 } 512 if (! header) { 513 psError(PS_ERR_IO, true, "Unable to find FITS header!\n"); 514 } else { 515 // Get the headers 516 char *stuff1 = strpbrk(timeString, " ,;"); 517 psString dateName = psStringNCopy(timeString, 518 strlen(timeString) - strlen(stuff1)); 519 char *stuff2 = strpbrk(stuff1, "abcdefghijklmnopqrstuvwxyz" 520 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); 521 psString timeName = psStringCopy(stuff2); 522 523 bool mdok = true; // Status of MD lookup 524 psString dateString = psMetadataLookupStr(&mdok, header, dateName); 525 psFree(dateName); 526 int day = 0, month = 0, year = 0; 527 if (sscanf(dateString, "%d-%d-%d", &day, &month, &year) != 3 && 528 sscanf(dateString, "%d/%d/%d", &day, &month, &year) != 3) { 529 psError(PS_ERR_IO, true, "Unable to read date: %s\n", dateString); 530 } else { 531 if (strstr(timeFormat, "BACKWARDS")) { 532 int temp = day; 533 day = year; 534 year = temp; 535 } 536 if (strstr(timeFormat, "PRE2000") || year < 2000) { 537 year += 2000; 538 } 539 540 psMetadataItem *timeItem = psMetadataLookup(header, timeName); 541 if (! timeItem) { 542 psError(PS_ERR_IO, false, "Unable to find time header: %s\n", 543 timeName); 544 } else if (timeItem->type == PS_DATA_STRING) { 545 // Time is a string, in the usual way: 546 psStringAppend(&dateString, "T%s", timeItem->data.V); 547 } else { 548 // Assume that time is specified in Second of Day 549 double seconds = NAN; 550 switch (timeItem->type) { 551 case PS_TYPE_S32: 552 seconds = timeItem->data.S32; 553 break; 554 case PS_TYPE_F32: 555 seconds = timeItem->data.F32; 556 break; 557 case PS_TYPE_F64: 558 seconds = timeItem->data.F64; 559 break; 560 default: 561 psError(PS_ERR_IO, true, "Time header (%s) is not of an " 562 "expected type: %x\n", timeName, timeItem->type); 563 } 564 // Now print to timeString as "hh:mm:ss.ss" 565 int hours = seconds / 3600; 566 seconds -= (double)hours * 3600.0; 567 int minutes = seconds / 60; 568 seconds -= (double)minutes * 60.0; 569 psStringAppend(&dateString, "T%02d:%02d:%02f", hours, minutes, 570 seconds); 571 } 572 time = psTimeFromISO(dateString, timeSys); 573 } // Reading date and time 574 psFree(timeName); 575 } // Reading headers 576 } else { 577 psError(PS_ERR_IO, true, "Not sure how to parse CELL.TIME (%s) --- trying " 578 "ISO\n", timeString); 579 time = psTimeFromISO(timeString, timeSys); 580 } // Interpreting the time string 581 } 331 case PS_TYPE_S32: 332 seconds = timeItem->data.S32; 582 333 break; 583 case PS_TYPE_F32: { 584 double timeValue = (double)timeItem->data.F32; 585 if (strcasecmp(timeFormat, "JD") == 0) { 586 time = psTimeFromJD(timeValue); 587 } else if (strcasecmp(timeFormat, "MJD") == 0) { 588 time = psTimeFromMJD(timeValue); 589 } else { 590 psError(PS_ERR_IO, true, "Not sure how to parse CELL.TIME (%f) --- trying " 591 "JD\n", timeValue); 592 time = psTimeFromJD(timeValue); 593 } 594 } 334 case PS_TYPE_F32: 335 seconds = timeItem->data.F32; 595 336 break; 596 case PS_TYPE_F64: { 597 double timeValue = (double)timeItem->data.F64; 598 if (strcasecmp(timeFormat, "JD") == 0) { 599 time = psTimeFromJD(timeValue); 600 } else if (strcasecmp(timeFormat, "MJD") == 0) { 601 time = psTimeFromMJD(timeValue); 602 } else { 603 psError(PS_ERR_IO, true, "Not sure how to parse CELL.TIME (%f) --- trying " 604 "JD\n", timeValue); 605 time = psTimeFromJD(timeValue); 606 } 607 } 337 case PS_TYPE_F64: 338 seconds = timeItem->data.F64; 608 339 break; 609 340 default: 610 psError(PS_ERR_IO, true, "Unable to parse CELL.TIME.\n"); 341 psError(PS_ERR_IO, true, "Time is not of an expected type: %x\n", timeItem->type); 342 return NULL; 611 343 } 344 // Now print to timeString as "hh:mm:ss.ss" 345 int hours = seconds / 3600; 346 seconds -= (double)hours * 3600.0; 347 int minutes = seconds / 60; 348 seconds -= (double)minutes * 60.0; 349 psStringAppend(&timeString, "%02d:%02d:%02f", hours, minutes, seconds); 350 } 351 psString dateTimeString = NULL; 352 psStringAppend(&dateTimeString, "%sT%s", dateString, timeString); 353 time = psTimeFromISO(dateTimeString, timeSys); 354 break; 355 } 356 case PS_DATA_STRING: { 357 psString timeString = concept->data.V; // String with the time 358 if (strcasecmp(timeFormat, "ISO") == 0) { 359 // timeString contains an ISO time 360 time = psTimeFromISO(timeString, timeSys); 361 } else if (strcasecmp(timeFormat, "JD") == 0) { 362 double timeValue = strtod (timeString, NULL); 363 time = psTimeFromJD(timeValue); 364 } else if (strcasecmp(timeFormat, "MJD") == 0) { 365 double timeValue = strtod (timeString, NULL); 366 time = psTimeFromMJD(timeValue); 612 367 } else { 613 psError(PS_ERR_IO, false, "Unable to find CELL.TIME in FORMATS.\n"); 614 } // Getting the format 615 } else { 616 psError(PS_ERR_IO, false, "Unable to find FORMATS in camera configuration.\n"); 617 } // Getting the formats 618 } // Getting CELL.TIME 619 620 psMetadataItem *item = psMetadataItemAllocPtr("CELL.TIME", PS_DATA_TIME, "Time of exposure", time); 368 psError(PS_ERR_IO, true, "Not sure how to parse CELL.TIME (%s) --- trying " 369 "ISO\n", timeString); 370 time = psTimeFromISO(timeString, timeSys); 371 } // Interpreting the time string 372 break; 373 } 374 case PS_TYPE_F32: { 375 double timeValue = (double)concept->data.F32; 376 if (strcasecmp(timeFormat, "JD") == 0) { 377 time = psTimeFromJD(timeValue); 378 } else if (strcasecmp(timeFormat, "MJD") == 0) { 379 time = psTimeFromMJD(timeValue); 380 } else { 381 psError(PS_ERR_IO, true, "Not sure how to parse CELL.TIME (%f) --- trying " 382 "JD\n", timeValue); 383 time = psTimeFromJD(timeValue); 384 } 385 break; 386 } 387 case PS_TYPE_F64: { 388 double timeValue = (double)concept->data.F64; 389 if (strcasecmp(timeFormat, "JD") == 0) { 390 time = psTimeFromJD(timeValue); 391 } else if (strcasecmp(timeFormat, "MJD") == 0) { 392 time = psTimeFromMJD(timeValue); 393 } else { 394 psError(PS_ERR_IO, true, "Not sure how to parse CELL.TIME (%f) --- trying " 395 "JD\n", timeValue); 396 time = psTimeFromJD(timeValue); 397 } 398 break; 399 } 400 default: 401 psError(PS_ERR_IO, true, "Unable to parse CELL.TIME.\n"); 402 return NULL; 403 } 404 405 psMetadataItem *item = psMetadataItemAllocPtr(pattern->name, PS_DATA_TIME, pattern->comment, time); 621 406 psFree(time); 622 407 return item; … … 624 409 625 410 // Correct a position --- in case the user wants FORTRAN indexing (like the FITS standard...) 626 static int fortranCorr(p mFPA *fpa, // FPA, contains the camera configuration411 static int fortranCorr(psMetadata *cameraFormat, // The camera format description 627 412 const char *name // Name of concept to check for FORTRAN indexing 628 413 ) 629 414 { 630 415 bool mdok = false; // Result of MD lookup 631 psMetadata *formats = psMetadataLookupMD(&mdok, fpa->camera, "FORMATS");416 psMetadata *formats = psMetadataLookupMD(&mdok, cameraFormat, "FORMATS"); 632 417 if (mdok && formats) { 633 418 psString format = psMetadataLookupStr(&mdok, formats, name); … … 639 424 } 640 425 641 psMetadataItem *pmConceptRead_CELL_X0(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db) 642 { 643 int x0 = pmConceptReadS32(fpa, chip, cell, db, "CELL.X0"); 644 x0 += fortranCorr(fpa, "CELL.X0"); 645 return psMetadataItemAllocS32("CELL.X0", "Position of (0,0) on the chip", x0); 646 } 647 648 649 psMetadataItem *pmConceptRead_CELL_Y0(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db) 650 { 651 int y0 = pmConceptReadS32(fpa, chip, cell, db, "CELL.Y0"); 652 y0 += fortranCorr(fpa, "CELL.X0"); 653 return psMetadataItemAllocS32("CELL.Y0", "Position of (0,0) on the chip", y0); 654 } 655 656 657 bool pmConceptWrite_CELL_TRIMSEC(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db) 658 { 659 psMetadataItem *trimsecItem = psMetadataLookup(cell->concepts, "CELL.TRIMSEC"); 660 psRegion *trimsec = trimsecItem->data.V; // The trimsec region 661 psString source = pmConceptReadString(fpa, chip, cell, db, "CELL.TRIMSEC.SOURCE"); // The source string 662 663 if (strcasecmp(source, "VALUE") == 0) { 664 // Check that it's the same value as stored in the camera 665 psString checkString = psMetadataLookupStr(NULL, cell->config, "CELL.TRIMSEC"); 666 psRegion checkRegion = psRegionFromString(checkString); 667 if (! COMPARE_REGIONS(&checkRegion, trimsec)) { 668 psError(PS_ERR_IO, true, "Target CELL.TRIMSEC is specified by value, and values don't " 669 "match.\n"); 670 return false; 671 } 672 return true; 673 } 674 675 if (strcasecmp(source, "HEADER") == 0) { 676 psMetadata *header = NULL; // The FITS header 677 if (cell->hdu) { 678 header = cell->hdu->header; 679 } else if (chip->hdu) { 680 header = chip->hdu->header; 681 } else if (fpa->hdu) { 682 header = fpa->hdu->header; 683 } 684 if (! header) { 685 psError(PS_ERR_IO, true, "Unable to find FITS header!\n"); 686 return false; 687 } 688 psMetadataAddItem(header, trimsecItem, PS_LIST_TAIL, PS_META_REPLACE); 689 return true; 690 } 691 692 psError(PS_ERR_IO, true, "CELL.TRIMSEC.SOURCE (%s) is not HEADER or VALUE.\n", source); 693 return false; 694 } 695 696 bool pmConceptWrite_CELL_BIASSEC(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db) 697 { 698 psMetadataItem *biassecItem = psMetadataLookup(cell->concepts, "CELL.BIASSEC"); 699 psList *biassecs = biassecItem->data.V; // The biassecs region list 700 701 if (biassecs->n == 0) { 702 psMetadataItem *noneItem = psMetadataItemAllocStr("CELL.BIASSEC", "Bias section", "NONE"); 703 pmConceptWriteItem(fpa, chip, cell, db, noneItem); 704 return true; 705 } 706 707 psString source = pmConceptReadString(fpa, chip, cell, db, "CELL.TRIMSEC.SOURCE"); // The source string 708 709 if (strcasecmp(source, "VALUE") == 0) { 710 // Check that it's the same value as stored in the camera 711 psString checkString = psMetadataLookupStr(NULL, cell->config, "CELL.BIASSEC"); 712 psList *checkList = psStringSplit(checkString, " ;"); 713 if (biassecs->n != checkList->n) { 714 psError(PS_ERR_IO, true, "Target CELL.BIASSEC is specified by value, but number of " 715 "entries doesn't match.\n"); 716 psFree(checkList); 717 return false; 718 } 719 720 // We don't care if the order matches or not 721 psVector *check = psVectorAlloc(biassecs->n, PS_TYPE_U8); // Vector to mark regions off 722 for (int i = 0; i < check->n; i++) { 723 check->data.U8[i] = 0; 724 } 725 psListIterator *biassecsIter = psListIteratorAlloc(biassecs, PS_LIST_HEAD, false); // Iterator 726 psListIterator *checkListIter = psListIteratorAlloc(checkList, PS_LIST_HEAD, false); 727 psRegion *biassec = NULL; // Region from iteration 728 while ((biassec = psListGetAndIncrement(biassecsIter))) { 729 psListIteratorSet(checkListIter, PS_LIST_HEAD); 730 psString checkRegionString = NULL; // Region string from iteration 731 int i = 0; // Counter 732 while ((checkRegionString = psListGetAndIncrement(checkListIter))) { 733 psRegion checkRegion = psRegionFromString(checkRegionString); 734 psTrace(__func__, 7, "Checking [%.0f:%.0f,%.0f:%.0f] against " 735 "[%.0f:%.0f,%.0f:%.0f]\n", biassec->x0, biassec->x1, biassec->y0, 736 biassec->y1, checkRegion.x0, checkRegion.x1, checkRegion.y0, 737 checkRegion.y1); 738 if (COMPARE_REGIONS(biassec, &checkRegion)) { 739 check->data.U8[i] = 1; 740 i++; 741 break; 742 } 743 i++; 744 } 745 } 746 747 bool allMatch = true; // Does everything match? 748 for (int i = 0; i < check->n; i++) { 749 if (check->data.U8[i] == 0) { 750 psError(PS_ERR_IO, true, "Target CELL.BIASSEC is specified by value, but values " 751 "don't match.\n"); 752 allMatch = false; 753 } 754 } 755 // Clean up 756 psFree(checkListIter); 757 psFree(checkList); 758 psFree(biassecsIter); 759 psFree(check); 760 761 return allMatch; 762 } 763 764 if (strcasecmp(source, "HEADER") == 0) { 765 psString keywordsString = psMetadataLookupStr(NULL, cell->config, "CELL.BIASSEC"); 766 psList *keywords = psStringSplit(keywordsString, " ,;"); 767 if (biassecs->n != keywords->n) { 768 psError(PS_ERR_IO, true, "Target CELL.BIASSEC is sepcified by headers, but the number " 769 "of headers doesn't match.\n"); 770 psFree(keywords); 771 return false; 772 } 773 774 psMetadata *header = NULL; // The FITS header 775 if (cell->hdu) { 776 header = cell->hdu->header; 777 } else if (chip->hdu) { 778 header = chip->hdu->header; 779 } else if (fpa->hdu) { 780 header = fpa->hdu->header; 781 } 782 if (! header) { 783 psError(PS_ERR_IO, true, "Unable to find FITS header!\n"); 784 psFree(keywords); 785 return false; 786 } 787 788 psListIterator *keywordsIter = psListIteratorAlloc(keywords, PS_LIST_HEAD, false); 789 psListIterator *biassecsIter = psListIteratorAlloc(biassecs, PS_LIST_HEAD, false); 790 psString keyword = NULL; // Header keyword from list 791 while ((keyword = psListGetAndIncrement(keywordsIter))) { 792 // Update the header 793 psRegion *biassec = psListGetAndIncrement(biassecsIter); 794 psString biassecString = psRegionToString(*biassec); 795 psMetadataAdd(header, PS_LIST_TAIL, keyword, PS_DATA_STRING | PS_META_REPLACE, "Bias section", 796 biassecString); 797 psFree(biassecString); 798 } 799 psFree(keywordsIter); 800 psFree(biassecsIter); 801 psFree(keywords); 802 803 return true; 804 } 805 806 psError(PS_ERR_IO, true, "CELL.BIASSEC.SOURCE (%s) is not HEADER or VALUE.\n", source); 807 return false; 808 } 809 810 // This function actually does both CELL.XBIN and CELL.YBIN, since if CELL.XBIN and CELL.YBIN are specified by 811 // the same header, we need to check to update them together. 812 bool pmConceptWrite_CELL_XBIN(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db) 813 { 814 psMetadataItem *xBinItem = psMetadataLookup(cell->concepts, "CELL.XBIN"); // Binning factor in x 815 psMetadataItem *yBinItem = psMetadataLookup(cell->concepts, "CELL.YBIN"); // Binning factor in y 816 817 const psMetadata *camera = fpa->camera; 818 psMetadata *translation = psMetadataLookupMD(NULL, camera, "TRANSLATION"); 819 psString xKeyword = psMetadataLookupStr(NULL, translation, "CELL.XBIN"); 820 psString yKeyword = psMetadataLookupStr(NULL, translation, "CELL.YBIN"); 821 if (strlen(xKeyword) > 0 && strcasecmp(xKeyword, yKeyword) != 0) { 822 pmConceptWriteToHeader(fpa, chip, cell, xBinItem); 823 xBinItem = NULL; 824 } 825 if (strlen(yKeyword) > 0 && strcasecmp(xKeyword, yKeyword) != 0) { 826 pmConceptWriteToHeader(fpa, chip, cell, yBinItem); 827 yBinItem = NULL; 828 } 829 if (strlen(xKeyword) > 0 && strlen(yKeyword) > 0 && strcasecmp(xKeyword, yKeyword) == 0) { 426 psMetadataItem *pmConceptParse_CELL_Positions(psMetadataItem *concept, psMetadataItem *pattern, psMetadata *cameraFormat, pmFPA *fpa, pmChip *chip, pmCell *cell) 427 { 428 assert(concept); 429 assert(cameraFormat); 430 431 if (concept->type != PS_TYPE_S32) { 432 psError(PS_ERR_IO, true, "Concept %s is not of type S32, as expected.\n", pattern->name); 433 return NULL; 434 } 435 int offset = concept->data.S32; 436 offset += fortranCorr(cameraFormat, pattern->name); 437 return psMetadataItemAllocS32(pattern->name, pattern->comment, offset); 438 } 439 440 441 442 psMetadataItem *pmConceptFormat_CELL_TRIMSEC(psMetadataItem *concept, psMetadata *cameraFormat, pmFPA *fpa, pmChip *chip, pmCell *cell) 443 { 444 assert(concept); 445 446 psRegion *trimsec = concept->data.V; // The trimsec region 447 psString trimsecString = psRegionToString(*trimsec); 448 psMetadataItem *formatted = psMetadataItemAllocStr(trimsecItem->name, trimsecItem->comment, 449 trimsecString); 450 psFree(trimsecString); 451 return formatted; 452 } 453 454 455 bool pmConceptFormat_CELL_BIASSEC(psMetadataItem *concept, psMetadata *cameraFormat, pmFPA *fpa, pmChip *chip, pmCell *cell) 456 { 457 psList *biassecs = concept->data.V; // The biassecs region list 458 psString biassecString = NULL; // String containing the biassecs 459 psListIterator *biassecsIter = psListIteratorAlloc(biassecs, PS_LIST_HEAD, false); // Iterator 460 psRegion *region = NULL; // Region from iteration 461 bool first = true; // Are we on the first one? 462 while ((region = psListGetAndIncrement(biassecsIter))) { 463 psString regionString = psRegionToString(*region); // The string region "[x0:x1,y0:y1]" 464 if (first) { 465 psStringAppend(&biassecString, "%s", regionString); 466 first = false; 467 } else { 468 psStringAppend(&biassecString, ";%s", regionString); // Put in a semi-colon 469 } 470 psFree(regionString); 471 } 472 psFree(biassecsIter); 473 psMetadataItem *formatted = psMetadataItemAllocStr(concept->name, concept->comment, biassecString); 474 psFree(biassecString); // Drop reference 475 return formatted; 476 } 477 478 479 // This function actually does both CELL.XBIN and CELL.YBIN if CELL.XBIN and CELL.YBIN are specified by the 480 // same header. 481 psMetadataItem *pmConceptFormat_CELL_XBIN(psMetadataItem *concept, psMetadata *cameraFormat, pmFPA *fpa, pmChip *chip, pmCell *cell) 482 { 483 assert(concept); 484 485 psMetadata *translation = psMetadataLookupMD(NULL, cameraFormat, "TRANSLATION"); 486 bool xBinOK = true, yBinOK = true; // Status of MD lookups 487 psString xKeyword = psMetadataLookupStr(&xBinOK, translation, "CELL.XBIN"); 488 psString yKeyword = psMetadataLookupStr(&yBinOK, translation, "CELL.YBIN"); 489 if (xBinOK && yBinOK && strlen(xKeyword) > 0 && strlen(yKeyword) > 0 && 490 strcasecmp(xKeyword, yKeyword) == 0) { 491 psMetadataItem *yBinItem = psMetadataLookup(cell->concepts, "CELL.YBIN"); // Binning factor in y 830 492 psString binString = psStringCopy(""); 831 psStringAppend(&binString, "%d,%d", xBinItem->data.S32, yBinItem->data.S32);832 psMetadataItem *binItem = psMetadataItemAllocStr( xKeyword, "Binning factor in x and y", binString);493 psStringAppend(&binString, "%d,%d", concept->data.S32, yBinItem->data.S32); 494 psMetadataItem *binItem = psMetadataItemAllocStr(concept->name, concept->comment, binString); 833 495 psFree(binString); 834 psMetadata *header = NULL; // The FITS header 835 if (cell->hdu) { 836 header = cell->hdu->header; 837 } else if (chip->hdu) { 838 header = chip->hdu->header; 839 } else if (fpa->hdu) { 840 header = fpa->hdu->header; 841 } 842 if (! header) { 843 psError(PS_ERR_IO, true, "Unable to find FITS header!\n"); 844 return false; 845 } 846 psMetadataAddItem(header, binItem, PS_LIST_TAIL, PS_META_REPLACE); 847 xBinItem = NULL; 848 yBinItem = NULL; 849 psFree(binItem); 850 } 851 852 // Do it in the usual way if we have to 853 if (xBinItem) { 854 pmConceptWriteItem(fpa, chip, cell, db, xBinItem); 855 } 856 if (yBinItem) { 857 pmConceptWriteItem(fpa, chip, cell, db, yBinItem); 858 } 859 860 return true; 861 } 862 863 // This is a dummy function, since CELL.YBIN is done by CELL.XBIN 864 bool pmConceptWrite_CELL_YBIN(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db) 865 { 866 return true; 867 } 868 869 870 871 bool pmConceptWrite_CELL_TIMESYS(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db) 872 { 873 psMetadataItem *sysItem = psMetadataLookup(cell->concepts, "CELL.TIMESYS"); 496 return binItem; 497 } 498 499 // Otherwise, there's no formatting required 500 return concept; 501 } 502 503 // Only need to format if both if CELL.XBIN and CELL.YBIN are not specified by the same header. 504 psMetadataItem *pmConceptFormat_CELL_YBIN(psMetadataItem *concept, psMetadata *cameraFormat, pmFPA *fpa, pmChip *chip, pmCell *cell) 505 { 506 assert(concept); 507 508 psMetadata *translation = psMetadataLookupMD(NULL, cameraFormat, "TRANSLATION"); 509 bool xBinOK = true, yBinOK = true; // Status of MD lookups 510 psString xKeyword = psMetadataLookupStr(&xBinOK, translation, "CELL.XBIN"); 511 psString yKeyword = psMetadataLookupStr(&yBinOK, translation, "CELL.YBIN"); 512 if (xBinOK && yBinOK && strlen(xKeyword) > 0 && strlen(yKeyword) > 0 && 513 strcasecmp(xKeyword, yKeyword) == 0) { 514 // Censor this --- it's already done (though no harm if it's done twice 515 return NULL; 516 } 517 518 // No formatting required 519 return concept; 520 } 521 522 523 psMetadataItem *pmConceptFormat_CELL_TIMESYS(psMetadataItem *concept, psMetadata *cameraFormat, pmFPA *fpa, pmChip *chip, pmCell *cell) 524 { 874 525 psString sys = NULL; // String to store 875 switch ( sysItem->data.S32) {526 switch (concept->data.S32) { 876 527 case PS_TIME_TAI: 877 528 sys = psStringCopy("TAI"); … … 889 540 sys = psStringCopy("Unknown"); 890 541 } 891 psMetadataItem *newItem = psMetadataItemAllocStr("CELL.TIMESYS", "Time system", sys); 892 bool success = pmConceptWriteItem(fpa, chip, cell, db, newItem); 893 psFree(newItem); 542 psMetadataItem *newItem = psMetadataItemAllocStr(concept->name, concept->comment, sys); 894 543 psFree(sys); 895 544 … … 897 546 } 898 547 899 bool pmConceptWrite_CELL_TIME(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db) 900 { 901 psMetadataItem *timeItem = psMetadataLookup(cell->concepts, "CELL.TIME"); 902 psTime *time = timeItem->data.V; // The time 903 psString dateTimeString = psTimeToISO(time); // String representation 904 905 psMetadata *formats = psMetadataLookupMD(NULL, fpa->camera, "FORMATS"); 548 psMetadataItem *pmConceptFormat_CELL_TIME(psMetadataItem *concept, psMetadata *cameraFormat, pmFPA *fpa, pmChip *chip, pmCell *cell) 549 { 550 psTime *time = concept->data.V; // The time 551 psMetadata *formats = psMetadataLookupMD(NULL, cameraFormat, "FORMATS"); 906 552 psString format = psMetadataLookupStr(NULL, formats, "CELL.TIME"); 907 553 908 if (strlen(format) == 0) { 909 // No format specified --> do it in the usual way (maybe it's a DB lookup) 910 psMetadataItem *newTimeItem = psMetadataItemAllocStr("CELL.TIME", "Time of observation", 911 dateTimeString); 912 bool success = pmConceptWriteItem(fpa, chip, cell, db, newTimeItem); 913 psFree(newTimeItem); 554 if (strlen(format) == 0 || strcasecmp(format, "ISO") == 0) { 555 psString dateTimeString = psTimeToISO(time); // String representation 556 psMetadataItem *item = psMetadataItemAllocStr(concept->name, concept->comment, dateTimeString); 914 557 psFree(dateTimeString); 915 return success; 916 } 917 if (strcasecmp(format, "ISO") == 0) { 918 // dateTimeString contains an ISO time 919 psMetadataItem *newTimeItem = psMetadataItemAllocStr("CELL.TIME", "Time of observation", 920 dateTimeString); 921 bool success = pmConceptWriteItem(fpa, chip, cell, db, newTimeItem); 922 psFree(newTimeItem); 558 return item; 559 } 560 if (strstr(format, "SEPARATE")) { 561 // We're working with two separate headers --- construct a list with the date and time separately 562 psString dateTimeString = psTimeToISO(time); // String representation 563 psList *dateTime = psStringSplit(dateTimeString, "T"); 923 564 psFree(dateTimeString); 924 return success; 925 } 926 if (strstr(format, "SEPARATE")) { 927 // We're working with two separate headers 928 psMetadata *header = NULL; // The FITS header 929 if (cell->hdu) { 930 header = cell->hdu->header; 931 } else if (chip->hdu) { 932 header = chip->hdu->header; 933 } else if (fpa->hdu) { 934 header = fpa->hdu->header; 935 } 936 if (! header) { 937 psError(PS_ERR_IO, true, "Unable to find FITS header!\n"); 938 psFree(dateTimeString); 939 return false; 940 } 941 942 // Get the headers 943 const psMetadata *camera = fpa->camera; 944 psMetadata *translation = psMetadataLookupMD(NULL, camera, "TRANSLATION"); 945 psString keywords = psMetadataLookupStr(NULL, translation, "CELL.TIME"); 946 psList *dateTimeKeywords = psStringSplit(keywords, " ,;"); 947 psString dateKeyword = psListGet(dateTimeKeywords, PS_LIST_HEAD); 948 psString timeKeyword = psListGet(dateTimeKeywords, PS_LIST_TAIL); 949 950 psList *dateTime = psStringSplit(dateTimeString, " T"); // Find the middle T 951 psString dateString = psListGet(dateTime, PS_LIST_HEAD); 952 psString timeString = psListGet(dateTime, PS_LIST_TAIL); 953 565 psString dateString = psListGet(dateTime, PS_LIST_HEAD); // The date string 566 psString timeString = psListGet(dateTime, PS_LIST_TAIL); // The time string 567 568 // Need to format the strings.... 954 569 // XXX: Couldn't be bothered doing these right now 955 570 if (strstr(format, "PRE2000")) { 956 571 psError(PS_ERR_IO, true, "Don't you realise it's the twenty-first century?\n"); 957 psFree(dateTimeString);958 // Should free other stuff, but this is work in progress959 572 return false; 960 573 } 961 574 if (strstr(format, "BACKWARDS")) { 962 575 psError(PS_ERR_IO, true, "You want it BACKWARDS? Not right now, thanks.\n"); 963 psFree(dateTimeString);964 // Should free other stuff, but this is work in progress965 576 return false; 966 577 } 967 578 968 bool success = true; 969 psMetadataItem *dateItem = psMetadataItemAllocStr(dateKeyword, "Date of observation", dateString); 970 psMetadataItem *timeItem = psMetadataItemAllocStr(timeKeyword, "Time of observation", timeString); 971 success = psMetadataAddItem(header, dateItem, PS_LIST_TAIL, PS_META_REPLACE) && 972 psMetadataAddItem(header, timeItem, PS_LIST_TAIL, PS_META_REPLACE); 973 974 psFree(dateTimeKeywords); 975 psFree(dateTime); 976 psFree(dateItem); 977 psFree(timeItem); 978 979 return success; 579 psMetadataItem *dateItem = psMetadataItemAllocStr(concept->name, "The date of observation", 580 dateString); 581 psMetadataItem *timeItem = psMetadataItemAllocStr(concept->name, "The time of observation", 582 timeString); 583 psFree(dateString); 584 psFree(timeString); 585 586 psListRemove(dateTime, PS_LIST_HEAD); 587 psListRemove(dateTime, PS_LIST_HEAD); 588 psListAdd(dateTime, PS_LIST_HEAD, dateItem); 589 psListAdd(dateTime, PS_LIST_TAIL, timeItem); 590 591 psMetadataItem *item = psMetadataItemAllocPtr(concept->name, PS_DATA_LIST, concept->comment, 592 dateTime); 593 return item; 980 594 } 981 595 if (strcasecmp(format, "MJD") == 0) { 982 596 double mjd = psTimeToMJD(time); 983 psMetadataItem *newTimeItem = psMetadataItemAllocF64("CELL.TIME", "MJD of observation", mjd); 984 bool success = pmConceptWriteItem(fpa, chip, cell, db, newTimeItem); 985 psFree(newTimeItem); 986 psFree(dateTimeString); 987 return success; 597 return psMetadataItemAllocF64(concept->name, concept->comment, mjd); 988 598 } 989 599 if (strcasecmp(format, "JD") == 0) { 990 600 double jd = psTimeToMJD(time); 991 psMetadataItem *newTimeItem = psMetadataItemAllocF64("CELL.TIME", "JD of observation", jd); 992 bool success = pmConceptWriteItem(fpa, chip, cell, db, newTimeItem); 993 psFree(newTimeItem); 994 psFree(dateTimeString); 995 return success; 996 } 997 998 psError(PS_ERR_IO, true, "Not sure how to write concept CELL.TIME (%s)\n", dateTimeString); 999 return false; 1000 } 1001 1002 bool pmConceptWrite_CELL_X0(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db) 1003 { 1004 psMetadataItem *x0item = psMetadataLookup(cell->concepts, "CELL.X0"); 1005 psMetadataItem *newItem = psMetadataItemAllocS32("CELL.X0", "Position of (0,0) on the chip", 1006 x0item->data.S32 - fortranCorr(fpa, "CELL.X0")); 1007 return pmConceptWriteItem(fpa, chip, cell, db, newItem); 1008 } 1009 1010 bool pmConceptWrite_CELL_Y0(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db) 1011 { 1012 psMetadataItem *y0item = psMetadataLookup(cell->concepts, "CELL.Y0"); 1013 psMetadataItem *newItem = psMetadataItemAllocS32("CELL.Y0", "Position of (0,0) on the chip", 1014 y0item->data.S32 - fortranCorr(fpa, "CELL.Y0")); 1015 return pmConceptWriteItem(fpa, chip, cell, db, newItem); 1016 } 1017 601 return psMetadataItemAllocF64("CELL.TIME", "JD of observation", jd); 602 } 603 604 psError(PS_ERR_IO, true, "Not sure how to format concept CELL.TIME (%s)\n", dateTimeString); 605 return NULL; 606 } 607 608 psMetadataItem *pmConceptFormat_CELL_Positions(psMetadataItem *concept, psMetadata *cameraFormat, pmFPA *fpa, pmChip *chip, pmCell *cell *db) 609 { 610 assert(concept); 611 assert(cameraFormat); 612 613 if (concept->type != PS_TYPE_S32) { 614 psError(PS_ERR_IO, true, "Concept %s is not of type S32, as expected.\n", pattern->name); 615 return NULL; 616 } 617 int offset = concept->data.S32; 618 offset -= fortranCorr(cameraFormat, concept->name); 619 return psMetadataItemAllocS32(concept->name, concept->comment, offset); 620 } 621
Note:
See TracChangeset
for help on using the changeset viewer.
