Changeset 5786 for trunk/archive/scripts/src/phase2/pmFPAConceptsGet.c
- Timestamp:
- Dec 13, 2005, 5:47:35 PM (21 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/archive/scripts/src/phase2/pmFPAConceptsGet.c
r5633 r5786 14 14 15 15 psMetadataItem *p_pmFPAConceptGetFromCamera(pmCell *cell, // The cell 16 const char *concept // Name of concept16 const char *concept // Name of concept 17 17 ) 18 18 { 19 19 if (cell) { 20 psMetadata *camera = cell->camera;// Camera data21 // Need the CELL.NAME first, which should be in the cell->concepts since creation of the cell22 bool mdStatus = true;// Status of MD lookup23 // Finally, the info that we want24 psMetadataItem *item = psMetadataLookup(camera, concept);25 return item;20 psMetadata *camera = cell->camera; // Camera data 21 // Need the CELL.NAME first, which should be in the cell->concepts since creation of the cell 22 bool mdStatus = true; // Status of MD lookup 23 // Finally, the info that we want 24 psMetadataItem *item = psMetadataLookup(camera, concept); 25 return item; 26 26 } 27 27 return NULL; 28 } 28 } 29 29 30 30 31 31 psMetadataItem *p_pmFPAConceptGetFromHeader(pmFPA *fpa, // The FPA that contains the chip 32 pmChip *chip, // The chip that contains the cell33 pmCell *cell, // The cell34 const char *concept // Name of concept35 ) 36 { 37 bool mdStatus = true; // Status of MD lookup32 pmChip *chip, // The chip that contains the cell 33 pmCell *cell, // The cell 34 const char *concept // Name of concept 35 ) 36 { 37 bool mdStatus = true; // Status of MD lookup 38 38 psMetadata *translation = psMetadataLookupMD(&mdStatus, fpa->camera, "TRANSLATION"); // FITS translation 39 39 if (! mdStatus) { 40 psError(PS_ERR_IO, false, "Unable to find TRANSLATION in camera configuration.\n");41 return NULL;40 psError(PS_ERR_IO, false, "Unable to find TRANSLATION in camera configuration.\n"); 41 return NULL; 42 42 } 43 43 … … 45 45 const char *keyword = psMetadataLookupString(&mdStatus, translation, concept); 46 46 if (mdStatus && strlen(keyword) > 0) { 47 // We have a FITS header to look up --- search each level48 if (cell && cell->hdu) {49 psMetadataItem *cellItem = psMetadataLookup(cell->hdu->header, keyword);50 if (cellItem) {51 // XXX: Need to clean up before returning52 return cellItem;53 }54 }55 56 if (chip && chip->hdu) {57 psMetadataItem *chipItem = psMetadataLookup(chip->hdu->header, keyword);58 if (chipItem) {59 // XXX: Need to clean up before returning60 return chipItem;61 }62 }63 64 if (fpa->hdu) {65 psMetadataItem *fpaItem = psMetadataLookup(fpa->hdu->header, keyword);66 if (fpaItem) {67 // XXX: Need to clean up before returning68 return fpaItem;69 }70 }71 72 if (fpa->phu) {73 psMetadataItem *fpaItem = psMetadataLookup(fpa->phu, keyword);74 if (fpaItem) {75 // XXX: Need to clean up before returning76 return fpaItem;77 }78 }47 // We have a FITS header to look up --- search each level 48 if (cell && cell->hdu) { 49 psMetadataItem *cellItem = psMetadataLookup(cell->hdu->header, keyword); 50 if (cellItem) { 51 // XXX: Need to clean up before returning 52 return cellItem; 53 } 54 } 55 56 if (chip && chip->hdu) { 57 psMetadataItem *chipItem = psMetadataLookup(chip->hdu->header, keyword); 58 if (chipItem) { 59 // XXX: Need to clean up before returning 60 return chipItem; 61 } 62 } 63 64 if (fpa->hdu) { 65 psMetadataItem *fpaItem = psMetadataLookup(fpa->hdu->header, keyword); 66 if (fpaItem) { 67 // XXX: Need to clean up before returning 68 return fpaItem; 69 } 70 } 71 72 if (fpa->phu) { 73 psMetadataItem *fpaItem = psMetadataLookup(fpa->phu, keyword); 74 if (fpaItem) { 75 // XXX: Need to clean up before returning 76 return fpaItem; 77 } 78 } 79 79 } 80 80 … … 86 86 // Look for a default 87 87 psMetadataItem *p_pmFPAConceptGetFromDefault(pmFPA *fpa, // The FPA that contains the chip 88 pmChip *chip, // The chip that contains the cell89 pmCell *cell, // The cell90 const char *concept // Name of concept91 ) 92 { 93 bool mdOK = true; // Status of MD lookup88 pmChip *chip, // The chip that contains the cell 89 pmCell *cell, // The cell 90 const char *concept // Name of concept 91 ) 92 { 93 bool mdOK = true; // Status of MD lookup 94 94 psMetadata *defaults = psMetadataLookupMD(&mdOK, fpa->camera, "DEFAULTS"); 95 95 if (! mdOK) { 96 psError(PS_ERR_IO, false, "Unable to find DEFAULTS in camera configuration.\n");97 return NULL;96 psError(PS_ERR_IO, false, "Unable to find DEFAULTS in camera configuration.\n"); 97 return NULL; 98 98 } 99 99 100 100 psMetadataItem *defItem = psMetadataLookup(defaults, concept); 101 101 if (defItem) { 102 if (defItem->type == PS_DATA_METADATA) {103 // A dependent default104 psTrace(__func__, 7, "Evaluating dependent default....\n");105 psMetadata *dependents = defItem->data.V; // The list of dependents106 // Find out what it depends on107 psString dependName = psStringCopy(concept);108 psStringAppend(&dependName, ".DEPEND");109 psString dependsOn = psMetadataLookupString(&mdOK, defaults, dependName);110 if (! mdOK) {111 psError(PS_ERR_IO, false, "Unable to find %s in camera configuration for dependent default"112 " --- ignored\n", dependName);113 // XXX: Need to clean up before returning114 return NULL;115 }116 psFree(dependName);117 // Find the value of the dependent concept118 psMetadataItem *depItem = p_pmFPAConceptGetFromHeader(fpa, chip, cell, dependsOn);119 if (! depItem) {120 psError(PS_ERR_IO, true, "Unable to find value for %s (required for %s)\n", dependsOn,121 concept);122 return NULL;123 }124 if (depItem->type != PS_DATA_STRING) {125 psError(PS_ERR_IO, true, "Value of %s is not of type string, as required for dependency"126 " --- ignored.\n", dependsOn);127 }128 129 defItem = psMetadataLookup(dependents, depItem->data.V);// This is now what we were after130 }102 if (defItem->type == PS_DATA_METADATA) { 103 // A dependent default 104 psTrace(__func__, 7, "Evaluating dependent default....\n"); 105 psMetadata *dependents = defItem->data.V; // The list of dependents 106 // Find out what it depends on 107 psString dependName = psStringCopy(concept); 108 psStringAppend(&dependName, ".DEPEND"); 109 psString dependsOn = psMetadataLookupString(&mdOK, defaults, dependName); 110 if (! mdOK) { 111 psError(PS_ERR_IO, false, "Unable to find %s in camera configuration for dependent default" 112 " --- ignored\n", dependName); 113 // XXX: Need to clean up before returning 114 return NULL; 115 } 116 psFree(dependName); 117 // Find the value of the dependent concept 118 psMetadataItem *depItem = p_pmFPAConceptGetFromHeader(fpa, chip, cell, dependsOn); 119 if (! depItem) { 120 psError(PS_ERR_IO, true, "Unable to find value for %s (required for %s)\n", dependsOn, 121 concept); 122 return NULL; 123 } 124 if (depItem->type != PS_DATA_STRING) { 125 psError(PS_ERR_IO, true, "Value of %s is not of type string, as required for dependency" 126 " --- ignored.\n", dependsOn); 127 } 128 129 defItem = psMetadataLookup(dependents, depItem->data.V); // This is now what we were after 130 } 131 131 } 132 132 133 133 // XXX: Need to clean up before returning 134 return defItem; // defItem is either NULL or points to what was desired134 return defItem; // defItem is either NULL or points to what was desired 135 135 } 136 136 … … 139 139 // XXX: Not tested 140 140 psMetadataItem *p_pmFPAConceptGetFromDB(pmFPA *fpa, // The FPA that contains the chip 141 pmChip *chip, // The chip that contains the cell142 pmCell *cell, // The cell143 psDB *db,// DB handle144 const char *concept // Name of concept141 pmChip *chip, // The chip that contains the cell 142 pmCell *cell, // The cell 143 psDB *db, // DB handle 144 const char *concept // Name of concept 145 145 ) 146 146 { 147 147 if (! db) { 148 // No database initialised149 return NULL;150 } 151 152 bool mdStatus = true; // Status of MD lookup148 // No database initialised 149 return NULL; 150 } 151 152 bool mdStatus = true; // Status of MD lookup 153 153 psMetadata *database = psMetadataLookupMD(&mdStatus, fpa->camera, "DATABASE"); 154 154 if (! mdStatus) { 155 // No error, because not everyone needs to use the DB156 return NULL;155 // No error, because not everyone needs to use the DB 156 return NULL; 157 157 } 158 158 159 159 psMetadata *dbLookup = psMetadataLookupMD(&mdStatus, database, concept); 160 160 if (dbLookup) { 161 const char *tableName = psMetadataLookupString(&mdStatus, dbLookup, "TABLE"); // Name of the table162 const char *colName = psMetadataLookupString(&mdStatus, dbLookup, "COLUMN"); // Name of the column163 const char *givenCols = psMetadataLookupString(&mdStatus, dbLookup, "GIVENDBCOL"); // Name of "where"164 // columns165 const char *givenPS = psMetadataLookupString(&mdStatus, dbLookup, "GIVENPS"); // Values for "where"166 // columns167 168 // Now, need to get the "given"s169 if (strlen(givenCols) || strlen(givenPS)) {170 psList *cols = papSplit(givenCols, ",;"); // List of column names171 psList *values = papSplit(givenPS, ",;"); // List of value names for the columns172 psMetadata *selection = psMetadataAlloc(); // The stuff to select in the DB173 if (cols->n != values->n) {174 psLogMsg(__func__, PS_LOG_WARN, "The GIVENDBCOL and GIVENPS entries for %s do not have "175 "the same number of entries --- ignored.\n", concept);176 } else {177 // Iterators for the lists178 psListIterator *colsIter = psListIteratorAlloc(cols, PS_LIST_HEAD, false);179 psListIterator *valuesIter = psListIteratorAlloc(values, PS_LIST_HEAD, false);180 char *column = NULL;// Name of the column181 while (column = psListGetAndIncrement(colsIter)) {182 char *name = psListGetAndIncrement(valuesIter); // Name for the value183 if (!strlen(column) || !strlen(name)) {184 psLogMsg(__func__, PS_LOG_WARN, "One of the columns or value names for %s is "185 " empty --- ignored.\n", concept);186 } else {187 // Search for the value name188 psMetadataItem *item = p_pmFPAConceptGetFromHeader(fpa, chip, cell, name);189 if (! item) {190 item = p_pmFPAConceptGetFromDefault(fpa, chip, cell, name);191 }192 if (! item) {193 psLogMsg(__func__, PS_LOG_ERROR, "Unable to find the value name %s for DB "194 " lookup on %s --- ignored.\n", name, concept);195 } else {196 // We need to create a new psMetadataItem. I don't think we can't simply hack197 // the existing one, since that could conceivably cause memory leaks198 psMetadataItem *newItem = psMetadataItemAlloc(concept, item->type,199 item->comment, item->data.V);200 psMetadataAddItem(selection, newItem, PS_LIST_TAIL, PS_META_REPLACE);201 psFree(newItem);202 }203 }204 psFree(name);205 psFree(column);206 } // Iterating through the columns207 psFree(colsIter);208 psFree(valuesIter);209 210 psArray *dbResult = psDBSelectRows(db, tableName, selection, 2); // Lookup result211 // Note that we use limit=2 in order to test if there are multiple rows returned212 213 psMetadataItem *result = NULL; // The final result of the DB lookup214 if (dbResult->n == 0) {215 psLogMsg(__func__, PS_LOG_WARN, "Unable to find any rows in DB for %s --- ignored\n", 216 concept);217 } else {218 if (dbResult-> n > 1) {219 psLogMsg(__func__, PS_LOG_WARN, "Multiple rows returned in DB lookup for %s --- "220 " using the first one only.\n", concept);221 }222 result = (psMetadataItem*)dbResult->data[0];223 }224 // XXX: Need to clean up before returning225 return result;226 }227 psFree(cols);228 psFree(values);229 }161 const char *tableName = psMetadataLookupString(&mdStatus, dbLookup, "TABLE"); // Name of the table 162 const char *colName = psMetadataLookupString(&mdStatus, dbLookup, "COLUMN"); // Name of the column 163 const char *givenCols = psMetadataLookupString(&mdStatus, dbLookup, "GIVENDBCOL"); // Name of "where" 164 // columns 165 const char *givenPS = psMetadataLookupString(&mdStatus, dbLookup, "GIVENPS"); // Values for "where" 166 // columns 167 168 // Now, need to get the "given"s 169 if (strlen(givenCols) || strlen(givenPS)) { 170 psList *cols = papSplit(givenCols, ",;"); // List of column names 171 psList *values = papSplit(givenPS, ",;"); // List of value names for the columns 172 psMetadata *selection = psMetadataAlloc(); // The stuff to select in the DB 173 if (cols->n != values->n) { 174 psLogMsg(__func__, PS_LOG_WARN, "The GIVENDBCOL and GIVENPS entries for %s do not have " 175 "the same number of entries --- ignored.\n", concept); 176 } else { 177 // Iterators for the lists 178 psListIterator *colsIter = psListIteratorAlloc(cols, PS_LIST_HEAD, false); 179 psListIterator *valuesIter = psListIteratorAlloc(values, PS_LIST_HEAD, false); 180 char *column = NULL; // Name of the column 181 while (column = psListGetAndIncrement(colsIter)) { 182 char *name = psListGetAndIncrement(valuesIter); // Name for the value 183 if (!strlen(column) || !strlen(name)) { 184 psLogMsg(__func__, PS_LOG_WARN, "One of the columns or value names for %s is " 185 " empty --- ignored.\n", concept); 186 } else { 187 // Search for the value name 188 psMetadataItem *item = p_pmFPAConceptGetFromHeader(fpa, chip, cell, name); 189 if (! item) { 190 item = p_pmFPAConceptGetFromDefault(fpa, chip, cell, name); 191 } 192 if (! item) { 193 psLogMsg(__func__, PS_LOG_ERROR, "Unable to find the value name %s for DB " 194 " lookup on %s --- ignored.\n", name, concept); 195 } else { 196 // We need to create a new psMetadataItem. I don't think we can't simply hack 197 // the existing one, since that could conceivably cause memory leaks 198 psMetadataItem *newItem = psMetadataItemAlloc(concept, item->type, 199 item->comment, item->data.V); 200 psMetadataAddItem(selection, newItem, PS_LIST_TAIL, PS_META_REPLACE); 201 psFree(newItem); 202 } 203 } 204 psFree(name); 205 psFree(column); 206 } // Iterating through the columns 207 psFree(colsIter); 208 psFree(valuesIter); 209 210 psArray *dbResult = psDBSelectRows(db, tableName, selection, 2); // Lookup result 211 // Note that we use limit=2 in order to test if there are multiple rows returned 212 213 psMetadataItem *result = NULL; // The final result of the DB lookup 214 if (dbResult->n == 0) { 215 psLogMsg(__func__, PS_LOG_WARN, "Unable to find any rows in DB for %s --- ignored\n", 216 concept); 217 } else { 218 if (dbResult-> n > 1) { 219 psLogMsg(__func__, PS_LOG_WARN, "Multiple rows returned in DB lookup for %s --- " 220 " using the first one only.\n", concept); 221 } 222 result = (psMetadataItem*)dbResult->data[0]; 223 } 224 // XXX: Need to clean up before returning 225 return result; 226 } 227 psFree(cols); 228 psFree(values); 229 } 230 230 } // Doing the "given"s. 231 231 … … 236 236 // Concept lookup 237 237 psMetadataItem *p_pmFPAConceptGet(pmFPA *fpa, // The FPA 238 pmChip *chip,// The chip239 pmCell *cell,// The cell240 psDB *db, // DB handle241 const char *concept // Concept name238 pmChip *chip,// The chip 239 pmCell *cell, // The cell 240 psDB *db, // DB handle 241 const char *concept // Concept name 242 242 ) 243 243 { … … 245 245 psMetadataItem *item = p_pmFPAConceptGetFromCamera(cell, concept); 246 246 if (! item) { 247 item = p_pmFPAConceptGetFromHeader(fpa, chip, cell, concept);247 item = p_pmFPAConceptGetFromHeader(fpa, chip, cell, concept); 248 248 } 249 249 if (! item) { … … 257 257 258 258 259 void p_pmFPAConceptGetF32(pmFPA *fpa, // The FPA260 pmChip *chip, // The chip261 pmCell *cell, // The cell262 psDB *db,// DB handle263 psMetadata *concepts, // The concepts MD264 const char *name, // Name of the concept265 const char *comment // Comment for concept259 void p_pmFPAConceptGetF32(pmFPA *fpa, // The FPA 260 pmChip *chip, // The chip 261 pmCell *cell, // The cell 262 psDB *db, // DB handle 263 psMetadata *concepts, // The concepts MD 264 const char *name, // Name of the concept 265 const char *comment // Comment for concept 266 266 ) 267 267 { … … 269 269 float value = NAN; 270 270 if (item) { 271 switch (item->type) {272 case PS_DATA_F32:273 value = item->data.F32;274 break;275 case PS_DATA_F64:276 // Assume it's OK to truncate to floating point from double277 value = (float)item->data.F64;278 break;279 case PS_DATA_S32:280 // Promote to float281 value = (float)item->data.S32;282 break;283 default:284 psError(PS_ERR_IO, true, "Concept %s (%s) is not of floating point type (%x) --- treating as "285 "undefined.\n", name, comment, item->type);286 }271 switch (item->type) { 272 case PS_DATA_F32: 273 value = item->data.F32; 274 break; 275 case PS_DATA_F64: 276 // Assume it's OK to truncate to floating point from double 277 value = (float)item->data.F64; 278 break; 279 case PS_DATA_S32: 280 // Promote to float 281 value = (float)item->data.S32; 282 break; 283 default: 284 psError(PS_ERR_IO, true, "Concept %s (%s) is not of floating point type (%x) --- treating as " 285 "undefined.\n", name, comment, item->type); 286 } 287 287 } else { 288 psError(PS_ERR_IO, true, "Concept %s (%s) is not defined.\n", name, comment);288 psError(PS_ERR_IO, true, "Concept %s (%s) is not defined.\n", name, comment); 289 289 } 290 290 psTrace(__func__, 7, "Adding %s (%s): %f\n", name, comment, value); 291 291 292 psMetadataAdd(concepts, PS_LIST_TAIL, name, PS_TYPE_F32 , comment, value);293 } 294 295 void p_pmFPAConceptGetF64(pmFPA *fpa, // The FPA296 pmChip *chip, // The chip297 pmCell *cell, // The cell298 psDB *db,// DB handle299 psMetadata *concepts, // The concepts MD300 const char *name, // Name of the concept301 const char *comment // Comment for concept292 psMetadataAdd(concepts, PS_LIST_TAIL, name, PS_TYPE_F32 | PS_META_REPLACE, comment, value); 293 } 294 295 void p_pmFPAConceptGetF64(pmFPA *fpa, // The FPA 296 pmChip *chip, // The chip 297 pmCell *cell, // The cell 298 psDB *db, // DB handle 299 psMetadata *concepts, // The concepts MD 300 const char *name, // Name of the concept 301 const char *comment // Comment for concept 302 302 ) 303 303 { … … 305 305 double value = NAN; 306 306 if (item) { 307 switch (item->type) {308 case PS_TYPE_F64:309 value = item->data.F64;310 break;311 case PS_TYPE_F32:312 // Promote to double313 value = (double)item->data.F32;314 break;315 case PS_TYPE_S32:316 // Promote to double317 value = (double)item->data.S32;318 break;319 default:320 psError(PS_ERR_IO, true, "Concept %s (%s) is not of double-precision floating point type (%x) "321 "--- treating as undefined.\n", name, comment, item->type);322 }307 switch (item->type) { 308 case PS_TYPE_F64: 309 value = item->data.F64; 310 break; 311 case PS_TYPE_F32: 312 // Promote to double 313 value = (double)item->data.F32; 314 break; 315 case PS_TYPE_S32: 316 // Promote to double 317 value = (double)item->data.S32; 318 break; 319 default: 320 psError(PS_ERR_IO, true, "Concept %s (%s) is not of double-precision floating point type (%x) " 321 "--- treating as undefined.\n", name, comment, item->type); 322 } 323 323 } else { 324 psError(PS_ERR_IO, true, "Concept %s (%s) is not defined.\n", name, comment);324 psError(PS_ERR_IO, true, "Concept %s (%s) is not defined.\n", name, comment); 325 325 } 326 326 psTrace(__func__, 7, "Adding %s (%s): %f\n", name, comment, value); 327 327 328 psMetadataAdd(concepts, PS_LIST_TAIL, name, PS_TYPE_F64 , comment, value);329 } 330 331 void p_pmFPAConceptGetS32(pmFPA *fpa, // The FPA332 pmChip *chip,// The chip333 pmCell *cell,// The cell334 psDB *db,// DB handle335 psMetadata *concepts, // The concepts MD336 const char *name, // Name of the concept337 const char *comment // Comment for concept328 psMetadataAdd(concepts, PS_LIST_TAIL, name, PS_TYPE_F64 | PS_META_REPLACE, comment, value); 329 } 330 331 void p_pmFPAConceptGetS32(pmFPA *fpa, // The FPA 332 pmChip *chip, // The chip 333 pmCell *cell, // The cell 334 psDB *db, // DB handle 335 psMetadata *concepts, // The concepts MD 336 const char *name, // Name of the concept 337 const char *comment // Comment for concept 338 338 ) 339 339 { … … 341 341 int value = 0; 342 342 if (item) { 343 switch (item->type) {344 case PS_TYPE_S32:345 value = item->data.S32;346 break;347 case PS_TYPE_F32:348 psLogMsg(__func__, PS_LOG_WARN, "Concept %s (%s) should be S32, but is F32 --- converting.\n",349 name, comment);350 value = (int)item->data.F32;351 break;352 case PS_TYPE_F64:353 psLogMsg(__func__, PS_LOG_WARN, "Concept %s (%s) should be S32, but is F64 --- converting.\n",354 name, comment);355 value = (int)item->data.F64;356 break;357 default:358 psError(PS_ERR_IO, true, "Concept %s (%s) is not of integer type (%x) --- treating as "359 "undefined.\n", name, comment, item->type);360 }343 switch (item->type) { 344 case PS_TYPE_S32: 345 value = item->data.S32; 346 break; 347 case PS_TYPE_F32: 348 psLogMsg(__func__, PS_LOG_WARN, "Concept %s (%s) should be S32, but is F32 --- converting.\n", 349 name, comment); 350 value = (int)item->data.F32; 351 break; 352 case PS_TYPE_F64: 353 psLogMsg(__func__, PS_LOG_WARN, "Concept %s (%s) should be S32, but is F64 --- converting.\n", 354 name, comment); 355 value = (int)item->data.F64; 356 break; 357 default: 358 psError(PS_ERR_IO, true, "Concept %s (%s) is not of integer type (%x) --- treating as " 359 "undefined.\n", name, comment, item->type); 360 } 361 361 } else { 362 psError(PS_ERR_IO, true, "Concept %s (%s) is not defined.\n", name, comment);362 psError(PS_ERR_IO, true, "Concept %s (%s) is not defined.\n", name, comment); 363 363 } 364 364 psTrace(__func__, 7, "Adding %s (%s): %d\n", name, comment, value); 365 366 psMetadataAdd(concepts, PS_LIST_TAIL, name, PS_TYPE_S32 , comment, value);365 366 psMetadataAdd(concepts, PS_LIST_TAIL, name, PS_TYPE_S32 | PS_META_REPLACE, comment, value); 367 367 } 368 368 369 369 void p_pmFPAConceptGetString(pmFPA *fpa, // The FPA 370 pmChip *chip, // The chip371 pmCell *cell, // The cell372 psDB *db,// DB handle373 psMetadata *concepts, // The concepts MD374 const char *name, // Name of the concept375 const char *comment // Comment for concept370 pmChip *chip, // The chip 371 pmCell *cell, // The cell 372 psDB *db, // DB handle 373 psMetadata *concepts, // The concepts MD 374 const char *name, // Name of the concept 375 const char *comment // Comment for concept 376 376 ) 377 377 { … … 379 379 psString value = NULL; 380 380 if (item) { 381 switch (item->type) {382 case PS_DATA_STRING:383 value = psMemIncrRefCounter(item->data.V);384 break;385 case PS_DATA_F32:386 psStringAppend(&value, "%f", item->data.F32);387 break;388 case PS_DATA_S32:389 psStringAppend(&value, "%d", item->data.S32);390 break;391 default:392 psError(PS_ERR_IO, true, "Concept %s (%s) is not of string type (%x) --- treating as "393 "undefined.\n", name, comment, item->type);394 }381 switch (item->type) { 382 case PS_DATA_STRING: 383 value = psMemIncrRefCounter(item->data.V); 384 break; 385 case PS_DATA_F32: 386 psStringAppend(&value, "%f", item->data.F32); 387 break; 388 case PS_DATA_S32: 389 psStringAppend(&value, "%d", item->data.S32); 390 break; 391 default: 392 psError(PS_ERR_IO, true, "Concept %s (%s) is not of string type (%x) --- treating as " 393 "undefined.\n", name, comment, item->type); 394 } 395 395 } else { 396 psError(PS_ERR_IO, true, "Concept %s (%s) is not defined.\n", name, comment);397 value = psStringCopy("");396 psError(PS_ERR_IO, true, "Concept %s (%s) is not defined.\n", name, comment); 397 value = psStringCopy(""); 398 398 } 399 399 psTrace(__func__, 7, "Adding %s (%s): %s\n", name, comment, value); 400 400 401 psMetadataAdd(concepts, PS_LIST_TAIL, name, PS_DATA_STRING , comment, value);401 psMetadataAdd(concepts, PS_LIST_TAIL, name, PS_DATA_STRING | PS_META_REPLACE, comment, value); 402 402 psFree(value); 403 403 } … … 409 409 410 410 // Ingest concepts for the FPA 411 void pmFPAIngestConcepts(pmFPA *fpa, // The FPA412 psDB *db// DB handle411 void pmFPAIngestConcepts(pmFPA *fpa, // The FPA 412 psDB *db // DB handle 413 413 ) 414 414 { 415 415 if (! fpa->concepts) { 416 fpa->concepts = psMetadataAlloc();416 fpa->concepts = psMetadataAlloc(); 417 417 } 418 418 … … 436 436 // FPA.RA 437 437 { 438 double ra = NAN;// The RA439 psMetadataItem *raItem = p_pmFPAConceptGet(fpa, NULL, NULL, db, "FPA.RA"); // The FPA.RA item440 if (raItem) {441 switch (raItem->type) {442 case PS_TYPE_F32:443 ra = raItem->data.F32;444 break;445 case PS_TYPE_F64:446 ra = raItem->data.F64;447 break;448 case PS_DATA_STRING:449 // Sexagesimal format450 {451 int big, medium;452 float small;453 // XXX: Upgrade path is to allow dd:mm.mmm454 if (sscanf(raItem->data.V, "%d:%d:%f", &big, &medium, &small) != 3 &&455 sscanf(raItem->data.V, "%d %d %f", &big, &medium, &small) != 3) {456 psError(PS_ERR_IO, true, "Cannot interpret FPA.RA: %s\n", raItem->data.V);457 break;458 }459 ra = abs(big) + (float)medium/60.0 + small/3600.0;460 if (big < 0) {461 ra *= -1.0;462 }463 }464 break;465 default:466 psError(PS_ERR_IO, true, "FPA.RA is of an unexpected type: %x\n", raItem->type);467 }468 469 // How to interpret the RA470 const psMetadata *camera = fpa->camera; // Camera configuration data471 bool mdok = true;// Status of MD lookup472 psMetadata *formats = psMetadataLookupMD(&mdok, camera, "FORMATS");473 if (mdok && formats) {474 psString raFormat = psMetadataLookupString(&mdok, formats, "FPA.RA");475 if (mdok && strlen(raFormat) > 0) {476 if (strcasecmp(raFormat, "HOURS") == 0) {477 ra *= M_PI / 12.0;478 } else if (strcasecmp(raFormat, "DEGREES") == 0) {479 ra *= M_PI / 180.0;480 } else if (strcasecmp(raFormat, "RADIANS") == 0) {481 // No action required482 } else {483 psLogMsg(__func__, PS_LOG_WARN, "Don't understand FPA.RA in FORMATS (%s) --- assuming"484 " HOURS.\n");485 ra *= M_PI / 12.0;486 }487 } else {488 psError(PS_ERR_IO, false, "Unable to find FPA.RA in FORMATS --- assuming HOURS.\n");489 ra *= M_PI / 12.0;490 }491 } else {492 psError(PS_ERR_IO, false, "Unable to find FORMAT metadata in camera configuration --- "493 "assuming format for FPA.RA is HOURS.\n");494 ra *= M_PI / 12.0;495 }496 } else {497 psError(PS_ERR_IO, false, "Couldn't find FPA.RA.\n");498 }499 500 psMetadataAdd(fpa->concepts, PS_LIST_TAIL, "FPA.RA", PS_DATA_F64, 501 "Right Ascension of the boresight (radians)", ra);438 double ra = NAN; // The RA 439 psMetadataItem *raItem = p_pmFPAConceptGet(fpa, NULL, NULL, db, "FPA.RA"); // The FPA.RA item 440 if (raItem) { 441 switch (raItem->type) { 442 case PS_TYPE_F32: 443 ra = raItem->data.F32; 444 break; 445 case PS_TYPE_F64: 446 ra = raItem->data.F64; 447 break; 448 case PS_DATA_STRING: 449 // Sexagesimal format 450 { 451 int big, medium; 452 float small; 453 // XXX: Upgrade path is to allow dd:mm.mmm 454 if (sscanf(raItem->data.V, "%d:%d:%f", &big, &medium, &small) != 3 && 455 sscanf(raItem->data.V, "%d %d %f", &big, &medium, &small) != 3) { 456 psError(PS_ERR_IO, true, "Cannot interpret FPA.RA: %s\n", raItem->data.V); 457 break; 458 } 459 ra = abs(big) + (float)medium/60.0 + small/3600.0; 460 if (big < 0) { 461 ra *= -1.0; 462 } 463 } 464 break; 465 default: 466 psError(PS_ERR_IO, true, "FPA.RA is of an unexpected type: %x\n", raItem->type); 467 } 468 469 // How to interpret the RA 470 const psMetadata *camera = fpa->camera; // Camera configuration data 471 bool mdok = true; // Status of MD lookup 472 psMetadata *formats = psMetadataLookupMD(&mdok, camera, "FORMATS"); 473 if (mdok && formats) { 474 psString raFormat = psMetadataLookupString(&mdok, formats, "FPA.RA"); 475 if (mdok && strlen(raFormat) > 0) { 476 if (strcasecmp(raFormat, "HOURS") == 0) { 477 ra *= M_PI / 12.0; 478 } else if (strcasecmp(raFormat, "DEGREES") == 0) { 479 ra *= M_PI / 180.0; 480 } else if (strcasecmp(raFormat, "RADIANS") == 0) { 481 // No action required 482 } else { 483 psLogMsg(__func__, PS_LOG_WARN, "Don't understand FPA.RA in FORMATS (%s) --- assuming" 484 " HOURS.\n"); 485 ra *= M_PI / 12.0; 486 } 487 } else { 488 psError(PS_ERR_IO, false, "Unable to find FPA.RA in FORMATS --- assuming HOURS.\n"); 489 ra *= M_PI / 12.0; 490 } 491 } else { 492 psError(PS_ERR_IO, false, "Unable to find FORMAT metadata in camera configuration --- " 493 "assuming format for FPA.RA is HOURS.\n"); 494 ra *= M_PI / 12.0; 495 } 496 } else { 497 psError(PS_ERR_IO, false, "Couldn't find FPA.RA.\n"); 498 } 499 500 psMetadataAdd(fpa->concepts, PS_LIST_TAIL, "FPA.RA", PS_DATA_F64 | PS_META_REPLACE, 501 "Right Ascension of the boresight (radians)", ra); 502 502 503 503 } … … 505 505 // FPA.DEC 506 506 { 507 double dec = NAN;// The DEC508 psMetadataItem *decItem = p_pmFPAConceptGet(fpa, NULL, NULL, db, "FPA.DEC"); // The FPA.DEC item509 if (decItem) {510 switch (decItem->type) {511 case PS_TYPE_F32:512 dec = decItem->data.F32;513 break;514 case PS_TYPE_F64:515 dec = decItem->data.F64;516 break;517 case PS_DATA_STRING:518 // Sexagesimal format519 {520 int big, medium;521 float small;522 // XXX: Upgrade path is to allow dd:mm.mmm523 if (sscanf(decItem->data.V, "%d:%d:%f", &big, &medium, &small) != 3 &&524 sscanf(decItem->data.V, "%d %d %f", &big, &medium, &small) != 3) {525 psError(PS_ERR_IO, true, "Cannot interpret FPA.DEC: %s\n", decItem->data.V);526 break;527 }528 dec = abs(big) + (float)medium/60.0 + small/3600.0;529 if (big < 0) {530 dec *= -1.0;531 }532 }533 break;534 default:535 psError(PS_ERR_IO, true, "FPA.DEC is of an unexpected type: %x\n", decItem->type);536 }537 538 // How to interpret the DEC539 const psMetadata *camera = fpa->camera; // Camera configuration data540 bool mdok = true;// Status of MD lookup541 psMetadata *formats = psMetadataLookupMD(&mdok, camera, "FORMATS");542 if (mdok && formats) {543 psString decFormat = psMetadataLookupString(&mdok, formats, "FPA.DEC");544 if (mdok && strlen(decFormat) > 0) {545 if (strcasecmp(decFormat, "HOURS") == 0) {546 dec *= M_PI / 12.0;547 } else if (strcasecmp(decFormat, "DEGREES") == 0) {548 dec *= M_PI / 180.0;549 } else if (strcasecmp(decFormat, "RADIANS") == 0) {550 // No action required551 } else {552 psLogMsg(__func__, PS_LOG_WARN, "Don't understand FPA.DEC in FORMATS (%s) --- "553 "assuming DEGREES.\n");554 dec *= M_PI / 180.0;555 }556 } else {557 psError(PS_ERR_IO, false, "Unable to find FPA.DEC in FORMATS --- assuming DEGREES.\n");558 dec *= M_PI / 180.0;559 }560 } else {561 psError(PS_ERR_IO, false, "Unable to find FORMATS metadata in camera configuration --- "562 "assuming format for FPA.DEC is DEGREES.\n");563 dec *= M_PI / 180.0;564 }565 } else {566 psError(PS_ERR_IO, false, "Couldn't find FPA.DEC.\n");567 }568 569 psMetadataAdd(fpa->concepts, PS_LIST_TAIL, "FPA.DEC", PS_DATA_F64, 570 "Declination of the boresight (radians)", dec);507 double dec = NAN; // The DEC 508 psMetadataItem *decItem = p_pmFPAConceptGet(fpa, NULL, NULL, db, "FPA.DEC"); // The FPA.DEC item 509 if (decItem) { 510 switch (decItem->type) { 511 case PS_TYPE_F32: 512 dec = decItem->data.F32; 513 break; 514 case PS_TYPE_F64: 515 dec = decItem->data.F64; 516 break; 517 case PS_DATA_STRING: 518 // Sexagesimal format 519 { 520 int big, medium; 521 float small; 522 // XXX: Upgrade path is to allow dd:mm.mmm 523 if (sscanf(decItem->data.V, "%d:%d:%f", &big, &medium, &small) != 3 && 524 sscanf(decItem->data.V, "%d %d %f", &big, &medium, &small) != 3) { 525 psError(PS_ERR_IO, true, "Cannot interpret FPA.DEC: %s\n", decItem->data.V); 526 break; 527 } 528 dec = abs(big) + (float)medium/60.0 + small/3600.0; 529 if (big < 0) { 530 dec *= -1.0; 531 } 532 } 533 break; 534 default: 535 psError(PS_ERR_IO, true, "FPA.DEC is of an unexpected type: %x\n", decItem->type); 536 } 537 538 // How to interpret the DEC 539 const psMetadata *camera = fpa->camera; // Camera configuration data 540 bool mdok = true; // Status of MD lookup 541 psMetadata *formats = psMetadataLookupMD(&mdok, camera, "FORMATS"); 542 if (mdok && formats) { 543 psString decFormat = psMetadataLookupString(&mdok, formats, "FPA.DEC"); 544 if (mdok && strlen(decFormat) > 0) { 545 if (strcasecmp(decFormat, "HOURS") == 0) { 546 dec *= M_PI / 12.0; 547 } else if (strcasecmp(decFormat, "DEGREES") == 0) { 548 dec *= M_PI / 180.0; 549 } else if (strcasecmp(decFormat, "RADIANS") == 0) { 550 // No action required 551 } else { 552 psLogMsg(__func__, PS_LOG_WARN, "Don't understand FPA.DEC in FORMATS (%s) --- " 553 "assuming DEGREES.\n"); 554 dec *= M_PI / 180.0; 555 } 556 } else { 557 psError(PS_ERR_IO, false, "Unable to find FPA.DEC in FORMATS --- assuming DEGREES.\n"); 558 dec *= M_PI / 180.0; 559 } 560 } else { 561 psError(PS_ERR_IO, false, "Unable to find FORMATS metadata in camera configuration --- " 562 "assuming format for FPA.DEC is DEGREES.\n"); 563 dec *= M_PI / 180.0; 564 } 565 } else { 566 psError(PS_ERR_IO, false, "Couldn't find FPA.DEC.\n"); 567 } 568 569 psMetadataAdd(fpa->concepts, PS_LIST_TAIL, "FPA.DEC", PS_DATA_F64 | PS_META_REPLACE, 570 "Declination of the boresight (radians)", dec); 571 571 572 572 } … … 577 577 578 578 // Ingest concepts for the chip 579 bool pmChipIngestConcepts(pmChip *chip, // The chip580 psDB *db// DB handle581 ) 582 { 583 pmFPA *fpa = chip->parent; // The parent FPA579 bool pmChipIngestConcepts(pmChip *chip, // The chip 580 psDB *db // DB handle 581 ) 582 { 583 pmFPA *fpa = chip->parent; // The parent FPA 584 584 585 585 if (! chip->concepts) { 586 chip->concepts = psMetadataAlloc();586 chip->concepts = psMetadataAlloc(); 587 587 } 588 588 … … 591 591 // Pau. 592 592 } 593 594 595 // Add corrective to a position --- in case the user wants FORTRAN indexing (like the FITS standard...) 596 static bool correctPosition(pmFPA *fpa, // FPA, contains the camera configuration 597 pmCell *cell, // Cell containing the concept to correct 598 const char *conceptName // Name of concept to correct 599 ) 600 { 601 bool mdok = false; // Result of MD lookup 602 psMetadata *formats = psMetadataLookupMD(&mdok, fpa->camera, "FORMATS"); 603 if (mdok && formats) { 604 psString format = psMetadataLookupString(&mdok, formats, conceptName); 605 if (mdok && strlen(format) > 0 && strcasecmp(format, "FORTRAN") == 0) { 606 psMetadataItem *valueItem = psMetadataLookup(cell->concepts, conceptName); 607 valueItem->data.S32 -= 1; 608 } 609 } 610 return true; 611 } 612 613 bool p_pmCellIngestConcept(pmFPA *fpa, // The FPA 614 pmChip *chip, // The chip 615 pmCell *cell, // The cell 616 psDB *db, // DB handle 617 const char *concept // Name of the concept 618 ) 619 { 620 if (strcmp(concept, "CELL.GAIN") == 0) { 621 p_pmFPAConceptGetF32(fpa, chip, cell, db, cell->concepts, "CELL.GAIN", "CCD gain (e/count)"); 622 } else if (strcmp(concept, "CELL.READNOISE") == 0) { 623 p_pmFPAConceptGetF32(fpa, chip, cell, db, cell->concepts, "CELL.READNOISE", "CCD read noise (e)"); 624 } else if (strcmp(concept, "CELL.SATURATION") == 0) { 625 p_pmFPAConceptGetF32(fpa, chip, cell, db, cell->concepts, "CELL.SATURATION", 626 "Saturation level (ADU)"); 627 } else if (strcmp(concept, "CELL.BAD") == 0) { 628 p_pmFPAConceptGetF32(fpa, chip, cell, db, cell->concepts, "CELL.BAD", "Bad level (ADU)"); 629 } else if (strcmp(concept, "CELL.XPARITY") == 0) { 630 p_pmFPAConceptGetS32(fpa, chip, cell, db, cell->concepts, "CELL.XPARITY", 631 "Orientation in x compared to the rest of the FPA"); 632 } else if (strcmp(concept, "CELL.YPARITY") == 0) { 633 p_pmFPAConceptGetS32(fpa, chip, cell, db, cell->concepts, "CELL.YPARITY", 634 "Orientation in y compared to the rest of the FPA"); 635 } else if (strcmp(concept, "CELL.READDIR") == 0) { 636 p_pmFPAConceptGetS32(fpa, chip, cell, db, cell->concepts, "CELL.READDIR", 637 "Read direction: 1=row, 2=col"); 638 } else if (strcmp(concept, "CELL.EXPOSURE") == 0) { // used to be READOUT.EXPOSURE 639 p_pmFPAConceptGetF32(fpa, chip, cell, db, cell->concepts, "CELL.EXPOSURE", "Exposure time (sec)"); 640 } else if (strcmp(concept, "CELL.DARKTIME") == 0) { // used to be READOUT.DARKTIME 641 p_pmFPAConceptGetF32(fpa, chip, cell, db, cell->concepts, "CELL.DARKTIME", 642 "Time since CCD flush (sec)"); 643 // These take some extra work 644 } else if (strcmp(concept, "CELL.TRIMSEC") == 0) { 645 psRegion *trimsec = psAlloc(sizeof(psRegion)); // Make space for a psRegion (usually passed by value) 646 647 psMetadataItem *secItem = p_pmFPAConceptGet(fpa, chip, cell, db, "CELL.TRIMSEC"); 648 if (! secItem) { 649 psError(PS_ERR_IO, false, "Couldn't find CELL.TRIMSEC.\n"); 650 *trimsec = psRegionSet(0.0, 0.0, 0.0, 0.0); 651 } else if (secItem->type != PS_DATA_STRING) { 652 psError(PS_ERR_IO, true, "CELL.TRIMSEC is not of type STR (%x)\n", secItem->type); 653 *trimsec = psRegionSet(0.0, 0.0, 0.0, 0.0); 654 } else { 655 psString section = secItem->data.V; // The section string 656 657 psMetadataItem *sourceItem = p_pmFPAConceptGet(fpa, chip, cell, db, "CELL.TRIMSEC.SOURCE"); 658 if (! sourceItem) { 659 psError(PS_ERR_IO, false, "Couldn't find CELL.TRIMSEC.SOURCE.\n"); 660 *trimsec = psRegionSet(0.0, 0.0, 0.0, 0.0); 661 } else if (sourceItem->type != PS_DATA_STRING) { 662 psError(PS_ERR_IO, true, "CELL.TRIMSEC.SOURCE is not of type STR (%x)\n", sourceItem->type); 663 *trimsec = psRegionSet(0.0, 0.0, 0.0, 0.0); 664 } else { 665 psString source = sourceItem->data.V; // The source string 666 667 if (strcasecmp(source, "VALUE") == 0) { 668 *trimsec = psRegionFromString(section); 669 } else if (strcasecmp(source, "HEADER") == 0) { 670 psMetadata *header = NULL; // The FITS header 671 if (cell->hdu) { 672 header = cell->hdu->header; 673 } else if (chip->hdu) { 674 header = chip->hdu->header; 675 } else if (fpa->hdu) { 676 header = fpa->hdu->header; 677 } 678 if (! header) { 679 psError(PS_ERR_IO, true, "Unable to find FITS header!\n"); 680 *trimsec = psRegionSet(0.0, 0.0, 0.0, 0.0); 681 } else { 682 bool mdok = true; // Status of MD lookup 683 psString secValue = psMetadataLookupString(&mdok, header, section); 684 if (! mdok || ! secValue) { 685 psError(PS_ERR_IO, false, "Unable to locate header %s\n", section); 686 *trimsec = psRegionSet(0.0, 0.0, 0.0, 0.0); 687 } else { 688 *trimsec = psRegionFromString(secValue); 689 } 690 } 691 } else { 692 psError(PS_ERR_IO, true, "CELL.TRIMSEC.SOURCE (%s) is not HEADER or VALUE --- trying " 693 "VALUE.\n", source); 694 *trimsec = psRegionFromString(section); 695 } // Value of CELL.TRIMSEC.SOURCE 696 } // Looking up CELL.TRIMSEC.SOURCE 697 } // Looking up CELL.TRIMSEC 698 699 psMetadataAdd(cell->concepts, PS_LIST_TAIL, "CELL.TRIMSEC", PS_DATA_UNKNOWN | PS_META_REPLACE, 700 "Trim section", trimsec); 701 psFree(trimsec); 702 703 } else if (strcmp(concept, "CELL.BIASSEC") == 0) { 704 psList *biassecs = psListAlloc(NULL); // List of bias sections 705 706 psMetadataItem *secItem = p_pmFPAConceptGet(fpa, chip, cell, db, "CELL.BIASSEC"); 707 if (! secItem) { 708 psError(PS_ERR_IO, false, "Couldn't find CELL.BIASSEC.\n"); 709 } else if (secItem->type != PS_DATA_STRING) { 710 psError(PS_ERR_IO, true, "CELL.BIASSEC is not of type STR (%x)\n", secItem->type); 711 } else { 712 psString sections = secItem->data.V; // The section string 713 714 psMetadataItem *sourceItem = p_pmFPAConceptGet(fpa, chip, cell, db, "CELL.BIASSEC.SOURCE"); 715 if (! sourceItem) { 716 psError(PS_ERR_IO, false, "Couldn't find CELL.BIASSEC.SOURCE.\n"); 717 } else if (sourceItem->type != PS_DATA_STRING) { 718 psError(PS_ERR_IO, true, "CELL.BIASSEC.SOURCE is not of type STR (%x)\n", sourceItem->type); 719 } else { 720 psString source = sourceItem->data.V; // The source string 721 722 psList *secList = papSplit(sections, " ;"); // List of sections 723 psListIterator *secIter = psListIteratorAlloc(secList, PS_LIST_HEAD, false); // Iterator over 724 // sections 725 psString aSection = NULL; // A section from the list 726 while (aSection = psListGetAndIncrement(secIter)) { 727 psRegion *region = psAlloc(sizeof(psRegion)); // Make space for a psRegion (usually passed 728 // by value) 729 730 if (strcasecmp(source, "VALUE") == 0) { 731 *region = psRegionFromString(aSection); 732 } else if (strcasecmp(source, "HEADER") == 0) { 733 psMetadata *header = NULL; // The FITS header 734 if (cell->hdu) { 735 header = cell->hdu->header; 736 } else if (chip->hdu) { 737 header = chip->hdu->header; 738 } else if (fpa->hdu) { 739 header = fpa->hdu->header; 740 } 741 if (! header) { 742 psError(PS_ERR_IO, true, "Unable to find FITS header!\n"); 743 *region = psRegionSet(0.0,0.0,0.0,0.0); 744 } else { 745 bool mdok = true; // Status of MD lookup 746 psString secValue = psMetadataLookupString(&mdok, header, aSection); 747 if (! mdok || ! secValue) { 748 psError(PS_ERR_IO, false, "Unable to locate header %s\n", aSection); 749 *region = psRegionSet(0.0,0.0,0.0,0.0); 750 } else { 751 *region = psRegionFromString(secValue); 752 } 753 } 754 } else { 755 psError(PS_ERR_IO, true, "CELL.BIASSEC.SOURCE (%s) is not HEADER or VALUE --- trying " 756 "VALUE.\n", source); 757 *region = psRegionFromString(aSection); 758 } // Value of CELL.BIASSEC.SOURCE 759 760 psListAdd(biassecs, PS_LIST_TAIL, region); 761 psFree(region); 762 } // Iterating over multiple sections 763 psFree(secIter); 764 psFree(secList); 765 } // Looking up CELL.BIASSEC.SOURCE 766 } // Looking up CELL.BIASSEC 767 768 psMetadataAdd(cell->concepts, PS_LIST_TAIL, "CELL.BIASSEC", PS_DATA_LIST | PS_META_REPLACE, 769 "Bias sections", biassecs); 770 psFree(biassecs); 771 772 } else if (strcmp(concept, "CELL.XBIN") == 0) { 773 int xBin = 1; // Binning factor in x 774 psMetadataItem *binItem = p_pmFPAConceptGet(fpa, chip, cell, db, "CELL.XBIN"); 775 if (! binItem) { 776 psError(PS_ERR_IO, false, "Couldn't find CELL.XBIN.\n"); 777 } else if (binItem->type == PS_DATA_STRING) { 778 psString binString = binItem->data.V; // The string containing the binning 779 if (sscanf(binString, "%d %*d", &xBin) != 1 && 780 sscanf(binString, "%d,%*d", &xBin) != 1) { 781 psError(PS_ERR_IO, true, "Unable to read string to get x binning: %s\n", binString); 782 } 783 } else if (binItem->type == PS_TYPE_S32) { 784 xBin = binItem->data.S32; 785 } else { 786 psError(PS_ERR_IO, true, "Note sure how to interpret CELL.XBIN of type %x --- assuming 1.\n", 787 binItem->type); 788 } 789 790 psMetadataAdd(cell->concepts, PS_LIST_TAIL, "CELL.XBIN", PS_TYPE_S32 | PS_META_REPLACE, 791 "Binning in x", xBin); 792 793 } else if (strcmp(concept, "CELL.YBIN") == 0) { 794 int yBin = 1; // Binning factor in y 795 psMetadataItem *binItem = p_pmFPAConceptGet(fpa, chip, cell, db, "CELL.YBIN"); 796 if (! binItem) { 797 psError(PS_ERR_IO, false, "Couldn't find CELL.YBIN.\n"); 798 } else if (binItem->type == PS_DATA_STRING) { 799 psString binString = binItem->data.V; // The string containing the binning 800 if (sscanf(binString, "%*d %d", &yBin) != 1 && 801 sscanf(binString, "%*d,%d", &yBin) != 1) { 802 psError(PS_ERR_IO, true, "Unable to read string to get y binning: %s\n", binString); 803 } 804 } else if (binItem->type == PS_TYPE_S32) { 805 yBin = binItem->data.S32; 806 } else { 807 psError(PS_ERR_IO, true, "Note sure how to interpret CELL.YBIN of type %x --- assuming 1.\n", 808 binItem->type); 809 } 810 811 psMetadataAdd(cell->concepts, PS_LIST_TAIL, "CELL.YBIN", PS_TYPE_S32 | PS_META_REPLACE, 812 "Binning in y", yBin); 813 814 } else if (strcmp(concept, "CELL.TIME") == 0 || strcmp(concept, "CELL.TIMESYS") == 0) { 815 // Do CELL.TIME and CELL.TIMESYS together 816 psTime *time = NULL; // The time 817 psTimeType timeSys = PS_TIME_UTC; // The time system 818 819 // CELL.TIMESYS 820 psMetadataItem *sysItem = p_pmFPAConceptGet(fpa, chip, cell, db, "CELL.TIMESYS"); 821 if (! sysItem) { 822 psError(PS_ERR_IO, true, "Couldn't find CELL.TIMESYS --- assuming UTC.\n"); 823 } else if (sysItem->type != PS_DATA_STRING) { 824 psError(PS_ERR_IO, true, "CELL.TIMESYS isn't of type STRING --- assuming UTC.\n"); 825 } else { 826 psString sys = sysItem->data.V; // The time system string 827 if (strcasecmp(sys, "TAI") == 0) { 828 timeSys = PS_TIME_TAI; 829 } else if (strcasecmp(sys, "UTC") == 0) { 830 timeSys = PS_TIME_UTC; 831 } else if (strcasecmp(sys, "UT1") == 0) { 832 timeSys = PS_TIME_UT1; 833 } else if (strcasecmp(sys, "TT") == 0) { 834 timeSys = PS_TIME_TT; 835 } else { 836 psError(PS_ERR_IO, true, "Can't interpret CELL.TIMESYS --- assuming UTC.\n"); 837 } 838 } 839 psMetadataAdd(cell->concepts, PS_LIST_TAIL, "CELL.TIMESYS", PS_TYPE_S32 | PS_META_REPLACE, 840 "Time system", timeSys); 841 842 psMetadataItem *timeItem = p_pmFPAConceptGet(fpa, chip, cell, db, "CELL.TIME"); 843 if (! timeItem) { 844 psError(PS_ERR_IO, false, "Couldn't find CELL.TIME.\n"); 845 } else { 846 // Get format 847 const psMetadata *camera = fpa->camera; // The camera configuration data 848 bool mdok = true; // Status of MD lookup 849 psMetadata *formats = psMetadataLookupMD(&mdok, camera, "FORMATS"); 850 if (mdok && formats) { 851 psString timeFormat = psMetadataLookupString(&mdok, formats, "CELL.TIME"); 852 if (mdok && strlen(timeFormat) > 0) { 853 switch (timeItem->type) { 854 case PS_DATA_STRING: 855 { 856 psString timeString = timeItem->data.V; // String with the time 857 if (strcasecmp(timeFormat, "ISO") == 0) { 858 // timeString contains an ISO time 859 time = psTimeFromISO(timeString, timeSys); 860 } else if (strstr(timeFormat, "SEPARATE")) { 861 // timeString contains headers for the date and time 862 psMetadata *header = NULL; // The FITS header 863 if (cell->hdu) { 864 header = cell->hdu->header; 865 } else if (chip->hdu) { 866 header = chip->hdu->header; 867 } else if (fpa->hdu) { 868 header = fpa->hdu->header; 869 } 870 if (! header) { 871 psError(PS_ERR_IO, true, "Unable to find FITS header!\n"); 872 } else { 873 // Get the headers 874 char *stuff1 = strpbrk(timeString, " ,;"); 875 psString dateName = psStringNCopy(timeString, 876 strlen(timeString) - strlen(stuff1)); 877 char *stuff2 = strpbrk(stuff1, "abcdefghijklmnopqrstuvwxyz" 878 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); 879 psString timeName = psStringCopy(stuff2); 880 881 bool mdok = true; // Status of MD lookup 882 psString dateString = psMetadataLookupString(&mdok, header, dateName); 883 psFree(dateName); 884 int day = 0, month = 0, year = 0; 885 if (sscanf(dateString, "%d-%d-%d", &day, &month, &year) != 3 && 886 sscanf(dateString, "%d/%d/%d", &day, &month, &year) != 3) { 887 psError(PS_ERR_IO, true, "Unable to read date: %s\n", dateString); 888 } else { 889 if (strstr(timeFormat, "BACKWARDS")) { 890 int temp = day; 891 day = year; 892 year = temp; 893 } 894 if (strstr(timeFormat, "PRE2000") || year < 2000) { 895 year += 2000; 896 } 897 898 psMetadataItem *timeItem = psMetadataLookup(header, timeName); 899 if (! timeItem) { 900 psError(PS_ERR_IO, false, "Unable to find time header: %s\n", 901 timeName); 902 } else if (timeItem->type == PS_DATA_STRING) { 903 // Time is a string, in the usual way: 904 psStringAppend(&dateString, "T%s", timeItem->data.V); 905 } else { 906 // Assume that time is specified in Second of Day 907 double seconds = NAN; 908 switch (timeItem->type) { 909 case PS_TYPE_S32: 910 seconds = timeItem->data.S32; 911 break; 912 case PS_TYPE_F32: 913 seconds = timeItem->data.F32; 914 break; 915 case PS_TYPE_F64: 916 seconds = timeItem->data.F64; 917 break; 918 default: 919 psError(PS_ERR_IO, true, "Time header (%s) is not of an " 920 "expected type: %x\n", timeName, timeItem->type); 921 } 922 // Now print to timeString as "hh:mm:ss.ss" 923 int hours = seconds / 3600; 924 seconds -= (double)hours * 3600.0; 925 int minutes = seconds / 60; 926 seconds -= (double)minutes * 60.0; 927 psStringAppend(&dateString, "T%02d:%02d:%02f", hours, minutes, 928 seconds); 929 } 930 time = psTimeFromISO(dateString, timeSys); 931 } // Reading date and time 932 psFree(timeName); 933 } // Reading headers 934 } else { 935 psError(PS_ERR_IO, true, "Not sure how to parse CELL.TIME (%s) --- trying " 936 "ISO\n", timeString); 937 time = psTimeFromISO(timeString, timeSys); 938 } // Interpreting the time string 939 } 940 break; 941 case PS_TYPE_F32: 942 { 943 double timeValue = (double)timeItem->data.F32; 944 if (strcasecmp(timeFormat, "JD") == 0) { 945 time = psTimeFromJD(timeValue); 946 } else if (strcasecmp(timeFormat, "MJD") == 0) { 947 time = psTimeFromMJD(timeValue); 948 } else { 949 psError(PS_ERR_IO, true, "Not sure how to parse CELL.TIME (%f) --- trying " 950 "JD\n", timeValue); 951 time = psTimeFromJD(timeValue); 952 } 953 } 954 break; 955 case PS_TYPE_F64: 956 { 957 double timeValue = (double)timeItem->data.F64; 958 if (strcasecmp(timeFormat, "JD") == 0) { 959 time = psTimeFromJD(timeValue); 960 } else if (strcasecmp(timeFormat, "MJD") == 0) { 961 time = psTimeFromMJD(timeValue); 962 } else { 963 psError(PS_ERR_IO, true, "Not sure how to parse CELL.TIME (%f) --- trying " 964 "JD\n", timeValue); 965 time = psTimeFromJD(timeValue); 966 } 967 } 968 break; 969 default: 970 psError(PS_ERR_IO, true, "Unable to parse CELL.TIME.\n"); 971 } 972 } else { 973 psError(PS_ERR_IO, false, "Unable to find CELL.TIME in FORMATS.\n"); 974 } // Getting the format 975 } else { 976 psError(PS_ERR_IO, false, "Unable to find FORMATS in camera configuration.\n"); 977 } // Getting the formats 978 } // Getting CELL.TIME 979 980 psMetadataAdd(cell->concepts, PS_LIST_TAIL, "CELL.TIME", PS_DATA_TIME | PS_META_REPLACE, 981 "Time of exposure", time); 982 psFree(time); 983 984 // These are new and experimental concepts: CELL.X0 and CELL.Y0 985 } else if (strcmp(concept, "CELL.X0") == 0) { 986 p_pmFPAConceptGetS32(fpa, chip, cell, db, cell->concepts, "CELL.X0", "Position of (0,0) on the chip"); 987 correctPosition(fpa, cell, "CELL.X0"); 988 } else if (strcmp(concept, "CELL.Y0") == 0) { 989 p_pmFPAConceptGetS32(fpa, chip, cell, db, cell->concepts, "CELL.Y0", "Position of (0,0) on the chip"); 990 correctPosition(fpa, cell, "CELL.Y0"); 991 } 992 993 return true; 994 } 995 593 996 594 997 595 998 // Ingest concepts for the cell 596 999 bool pmCellIngestConcepts(pmCell *cell, // The cell 597 psDB *db// DB handle598 ) 599 { 600 pmChip *chip = cell->parent; // The parent chip601 pmFPA *fpa = chip->parent; // The parent FPA1000 psDB *db // DB handle 1001 ) 1002 { 1003 pmChip *chip = cell->parent; // The parent chip 1004 pmFPA *fpa = chip->parent; // The parent FPA 602 1005 603 1006 if (! cell->concepts) { 604 cell->concepts = psMetadataAlloc();1007 cell->concepts = psMetadataAlloc(); 605 1008 } 606 1009 607 1010 // CELL.NAME --- added by pmFPAConstruct 608 1011 609 // CELL.GAIN 610 p_pmFPAConceptGetF32(fpa, chip, cell, db, cell->concepts, "CELL.GAIN", "CCD gain (e/count)"); 611 612 // CELL.READNOISE 613 p_pmFPAConceptGetF32(fpa, chip, cell, db, cell->concepts, "CELL.READNOISE", "CCD read noise (e)"); 614 615 // CELL.SATURATION 616 p_pmFPAConceptGetF32(fpa, chip, cell, db, cell->concepts, "CELL.SATURATION", "Saturation level (ADU)"); 617 618 // CELL.BAD 619 p_pmFPAConceptGetF32(fpa, chip, cell, db, cell->concepts, "CELL.BAD", "Bad level (ADU)"); 620 621 // CELL.XPARITY 622 p_pmFPAConceptGetS32(fpa, chip, cell, db, cell->concepts, "CELL.XPARITY", "Orientation in x compared to the " 623 "rest of the FPA"); 624 625 // CELL.YPARITY 626 p_pmFPAConceptGetS32(fpa, chip, cell, db, cell->concepts, "CELL.YPARITY", "Orientation in y compared to the " 627 "rest of the FPA"); 628 629 // CELL.READDIR 630 p_pmFPAConceptGetS32(fpa, chip, cell, db, cell->concepts, "CELL.READDIR", "Read direction: 1=row, 2=col"); 1012 p_pmCellIngestConcept(fpa, chip, cell, db, "CELL.GAIN"); 1013 p_pmCellIngestConcept(fpa, chip, cell, db, "CELL.READNOISE"); 1014 p_pmCellIngestConcept(fpa, chip, cell, db, "CELL.SATURATION"); 1015 p_pmCellIngestConcept(fpa, chip, cell, db, "CELL.BAD"); 1016 p_pmCellIngestConcept(fpa, chip, cell, db, "CELL.XPARITY"); 1017 p_pmCellIngestConcept(fpa, chip, cell, db, "CELL.YPARITY"); 1018 p_pmCellIngestConcept(fpa, chip, cell, db, "CELL.READDIR"); 631 1019 632 1020 // These used to be pmReadoutGetExposure and pmReadoutGetDarkTime, but that doesn't really make sense at … … 634 1022 // REALLY derived? They're not in the FITS headers, because a readout is a plane in a 3D image. We'll 635 1023 // have to dream up some additional suffix to specify these, but for now.... 636 637 // CELL.EXPOSURE (used to be READOUT.EXPOSURE) 638 p_pmFPAConceptGetF32(fpa, chip, cell, db, cell->concepts, "CELL.EXPOSURE", "Exposure time (sec)"); 639 640 // CELL.DARKTIME (used to be READOUT.DARKTIME) 641 p_pmFPAConceptGetF32(fpa, chip, cell, db, cell->concepts, "CELL.DARKTIME", "Time since CCD flush (sec)"); 642 643 // These take some extra work 644 645 // CELL.TRIMSEC 646 { 647 psRegion *trimsec = psAlloc(sizeof(psRegion)); // Make space for a psRegion (usually passed by value) 648 649 psMetadataItem *secItem = p_pmFPAConceptGet(fpa, chip, cell, db, "CELL.TRIMSEC"); 650 if (! secItem) { 651 psError(PS_ERR_IO, false, "Couldn't find CELL.TRIMSEC.\n"); 652 *trimsec = psRegionSet(0.0, 0.0, 0.0, 0.0); 653 } else if (secItem->type != PS_DATA_STRING) { 654 psError(PS_ERR_IO, true, "CELL.TRIMSEC is not of type STR (%x)\n", secItem->type); 655 *trimsec = psRegionSet(0.0, 0.0, 0.0, 0.0); 656 } else { 657 psString section = secItem->data.V; // The section string 658 659 psMetadataItem *sourceItem = p_pmFPAConceptGet(fpa, chip, cell, db, "CELL.TRIMSEC.SOURCE"); 660 if (! sourceItem) { 661 psError(PS_ERR_IO, false, "Couldn't find CELL.TRIMSEC.SOURCE.\n"); 662 *trimsec = psRegionSet(0.0, 0.0, 0.0, 0.0); 663 } else if (sourceItem->type != PS_DATA_STRING) { 664 psError(PS_ERR_IO, true, "CELL.TRIMSEC.SOURCE is not of type STR (%x)\n", sourceItem->type); 665 *trimsec = psRegionSet(0.0, 0.0, 0.0, 0.0); 666 } else { 667 psString source = sourceItem->data.V; // The source string 668 669 if (strcasecmp(source, "VALUE") == 0) { 670 *trimsec = psRegionFromString(section); 671 } else if (strcasecmp(source, "HEADER") == 0) { 672 psMetadata *header = NULL; // The FITS header 673 if (cell->hdu) { 674 header = cell->hdu->header; 675 } else if (chip->hdu) { 676 header = chip->hdu->header; 677 } else if (fpa->hdu) { 678 header = fpa->hdu->header; 679 } 680 if (! header) { 681 psError(PS_ERR_IO, true, "Unable to find FITS header!\n"); 682 *trimsec = psRegionSet(0.0, 0.0, 0.0, 0.0); 683 } else { 684 bool mdok = true; // Status of MD lookup 685 psString secValue = psMetadataLookupString(&mdok, header, section); 686 if (! mdok || ! secValue) { 687 psError(PS_ERR_IO, false, "Unable to locate header %s\n", section); 688 *trimsec = psRegionSet(0.0, 0.0, 0.0, 0.0); 689 } else { 690 *trimsec = psRegionFromString(secValue); 691 } 692 } 693 } else { 694 psError(PS_ERR_IO, true, "CELL.TRIMSEC.SOURCE (%s) is not HEADER or VALUE --- trying " 695 "VALUE.\n", source); 696 *trimsec = psRegionFromString(section); 697 } // Value of CELL.TRIMSEC.SOURCE 698 } // Looking up CELL.TRIMSEC.SOURCE 699 } // Looking up CELL.TRIMSEC 700 701 psMetadataAdd(cell->concepts, PS_LIST_TAIL, "CELL.TRIMSEC", PS_DATA_UNKNOWN, 702 "Trim section", trimsec); 703 psFree(trimsec); 704 } 705 706 // CELL.BIASSEC 707 { 708 psList *biassecs = psListAlloc(NULL); // List of bias sections 709 710 psMetadataItem *secItem = p_pmFPAConceptGet(fpa, chip, cell, db, "CELL.BIASSEC"); 711 if (! secItem) { 712 psError(PS_ERR_IO, false, "Couldn't find CELL.BIASSEC.\n"); 713 } else if (secItem->type != PS_DATA_STRING) { 714 psError(PS_ERR_IO, true, "CELL.BIASSEC is not of type STR (%x)\n", secItem->type); 715 } else { 716 psString sections = secItem->data.V; // The section string 717 718 psMetadataItem *sourceItem = p_pmFPAConceptGet(fpa, chip, cell, db, "CELL.BIASSEC.SOURCE"); 719 if (! sourceItem) { 720 psError(PS_ERR_IO, false, "Couldn't find CELL.BIASSEC.SOURCE.\n"); 721 } else if (sourceItem->type != PS_DATA_STRING) { 722 psError(PS_ERR_IO, true, "CELL.BIASSEC.SOURCE is not of type STR (%x)\n", sourceItem->type); 723 } else { 724 psString source = sourceItem->data.V; // The source string 725 726 psList *secList = papSplit(sections, " ;"); // List of sections 727 psListIterator *secIter = psListIteratorAlloc(secList, PS_LIST_HEAD, false); // Iterator over 728 // sections 729 psString aSection = NULL; // A section from the list 730 while (aSection = psListGetAndIncrement(secIter)) { 731 psRegion *region = psAlloc(sizeof(psRegion)); // Make space for a psRegion (usually passed 732 // by value) 733 734 if (strcasecmp(source, "VALUE") == 0) { 735 *region = psRegionFromString(aSection); 736 } else if (strcasecmp(source, "HEADER") == 0) { 737 psMetadata *header = NULL; // The FITS header 738 if (cell->hdu) { 739 header = cell->hdu->header; 740 } else if (chip->hdu) { 741 header = chip->hdu->header; 742 } else if (fpa->hdu) { 743 header = fpa->hdu->header; 744 } 745 if (! header) { 746 psError(PS_ERR_IO, true, "Unable to find FITS header!\n"); 747 *region = psRegionSet(0.0,0.0,0.0,0.0); 748 } else { 749 bool mdok = true; // Status of MD lookup 750 psString secValue = psMetadataLookupString(&mdok, header, aSection); 751 if (! mdok || ! secValue) { 752 psError(PS_ERR_IO, false, "Unable to locate header %s\n", aSection); 753 *region = psRegionSet(0.0,0.0,0.0,0.0); 754 } else { 755 *region = psRegionFromString(secValue); 756 } 757 } 758 } else { 759 psError(PS_ERR_IO, true, "CELL.BIASSEC.SOURCE (%s) is not HEADER or VALUE --- trying " 760 "VALUE.\n", source); 761 *region = psRegionFromString(aSection); 762 } // Value of CELL.BIASSEC.SOURCE 763 764 psListAdd(biassecs, PS_LIST_TAIL, region); 765 psFree(region); 766 } // Iterating over multiple sections 767 psFree(secIter); 768 psFree(secList); 769 } // Looking up CELL.BIASSEC.SOURCE 770 } // Looking up CELL.BIASSEC 771 772 psMetadataAdd(cell->concepts, PS_LIST_TAIL, "CELL.BIASSEC", PS_DATA_LIST, "Bias sections", biassecs); 773 psFree(biassecs); 774 } 775 776 // CELL.XBIN 777 { 778 int xBin = 1; // Binning factor in x 779 psMetadataItem *binItem = p_pmFPAConceptGet(fpa, chip, cell, db, "CELL.XBIN"); 780 if (! binItem) { 781 psError(PS_ERR_IO, false, "Couldn't find CELL.XBIN.\n"); 782 } else if (binItem->type == PS_DATA_STRING) { 783 psString binString = binItem->data.V; // The string containing the binning 784 if (sscanf(binString, "%d %*d", &xBin) != 1 && 785 sscanf(binString, "%d,%*d", &xBin) != 1) { 786 psError(PS_ERR_IO, true, "Unable to read string to get x binning: %s\n", binString); 787 } 788 } else if (binItem->type == PS_TYPE_S32) { 789 xBin = binItem->data.S32; 790 } else { 791 psError(PS_ERR_IO, true, "Note sure how to interpret CELL.XBIN of type %x --- assuming 1.\n", 792 binItem->type); 793 } 794 795 psMetadataAdd(cell->concepts, PS_LIST_TAIL, "CELL.XBIN", PS_TYPE_S32, "Binning in x", xBin); 796 } 797 798 // CELL.XBIN 799 { 800 int yBin = 1; // Binning factor in y 801 psMetadataItem *binItem = p_pmFPAConceptGet(fpa, chip, cell, db, "CELL.YBIN"); 802 if (! binItem) { 803 psError(PS_ERR_IO, false, "Couldn't find CELL.YBIN.\n"); 804 } else if (binItem->type == PS_DATA_STRING) { 805 psString binString = binItem->data.V; // The string containing the binning 806 if (sscanf(binString, "%*d %d", &yBin) != 1 && 807 sscanf(binString, "%*d,%d", &yBin) != 1) { 808 psError(PS_ERR_IO, true, "Unable to read string to get y binning: %s\n", binString); 809 } 810 } else if (binItem->type == PS_TYPE_S32) { 811 yBin = binItem->data.S32; 812 } else { 813 psError(PS_ERR_IO, true, "Note sure how to interpret CELL.YBIN of type %x --- assuming 1.\n", 814 binItem->type); 815 } 816 817 psMetadataAdd(cell->concepts, PS_LIST_TAIL, "CELL.YBIN", PS_TYPE_S32, "Binning in y", yBin); 818 } 819 820 // CELL.TIME and CELL.TIMESYS 821 { 822 psTime *time = NULL; // The time 823 psTimeType timeSys = PS_TIME_UTC; // The time system 824 825 // CELL.TIMESYS 826 psMetadataItem *sysItem = p_pmFPAConceptGet(fpa, chip, cell, db, "CELL.TIMESYS"); 827 if (! sysItem) { 828 psError(PS_ERR_IO, true, "Couldn't find CELL.TIMESYS --- assuming UTC.\n"); 829 } else if (sysItem->type != PS_DATA_STRING) { 830 psError(PS_ERR_IO, true, "CELL.TIMESYS isn't of type STRING --- assuming UTC.\n"); 831 } else { 832 psString sys = sysItem->data.V; // The time system string 833 if (strcasecmp(sys, "TAI") == 0) { 834 timeSys = PS_TIME_TAI; 835 } else if (strcasecmp(sys, "UTC") == 0) { 836 timeSys = PS_TIME_UTC; 837 } else if (strcasecmp(sys, "UT1") == 0) { 838 timeSys = PS_TIME_UT1; 839 } else if (strcasecmp(sys, "TT") == 0) { 840 timeSys = PS_TIME_TT; 841 } else { 842 psError(PS_ERR_IO, true, "Can't interpret CELL.TIMESYS --- assuming UTC.\n"); 843 } 844 } 845 psMetadataAdd(cell->concepts, PS_LIST_TAIL, "CELL.TIMESYS", PS_TYPE_S32, "Time system", timeSys); 846 847 psMetadataItem *timeItem = p_pmFPAConceptGet(fpa, chip, cell, db, "CELL.TIME"); 848 if (! timeItem) { 849 psError(PS_ERR_IO, false, "Couldn't find CELL.TIME.\n"); 850 } else { 851 // Get format 852 const psMetadata *camera = fpa->camera; // The camera configuration data 853 bool mdok = true; // Status of MD lookup 854 psMetadata *formats = psMetadataLookupMD(&mdok, camera, "FORMATS"); 855 if (mdok && formats) { 856 psString timeFormat = psMetadataLookupString(&mdok, formats, "CELL.TIME"); 857 if (mdok && strlen(timeFormat) > 0) { 858 switch (timeItem->type) { 859 case PS_DATA_STRING: 860 { 861 psString timeString = timeItem->data.V; // String with the time 862 if (strcasecmp(timeFormat, "ISO") == 0) { 863 // timeString contains an ISO time 864 time = psTimeFromISO(timeString, timeSys); 865 } else if (strstr(timeFormat, "SEPARATE")) { 866 // timeString contains headers for the date and time 867 psMetadata *header = NULL; // The FITS header 868 if (cell->hdu) { 869 header = cell->hdu->header; 870 } else if (chip->hdu) { 871 header = chip->hdu->header; 872 } else if (fpa->hdu) { 873 header = fpa->hdu->header; 874 } 875 if (! header) { 876 psError(PS_ERR_IO, true, "Unable to find FITS header!\n"); 877 } else { 878 // Get the headers 879 char *stuff1 = strpbrk(timeString, " ,;"); 880 psString dateName = psStringNCopy(timeString, 881 strlen(timeString) - strlen(stuff1)); 882 char *stuff2 = strpbrk(stuff1, 883 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); 884 psString timeName = psStringCopy(stuff2); 885 886 bool mdok = true; // Status of MD lookup 887 psString dateString = psMetadataLookupString(&mdok, header, dateName); 888 psFree(dateName); 889 int day = 0, month = 0, year = 0; 890 if (sscanf(dateString, "%d-%d-%d", &day, &month, &year) != 3 && 891 sscanf(dateString, "%d/%d/%d", &day, &month, &year) != 3) { 892 psError(PS_ERR_IO, true, "Unable to read date: %s\n", dateString); 893 } else { 894 if (strstr(timeFormat, "BACKWARDS")) { 895 int temp = day; 896 day = year; 897 year = temp; 898 } 899 if (strstr(timeFormat, "PRE2000") || year < 2000) { 900 year += 2000; 901 } 902 903 psMetadataItem *timeItem = psMetadataLookup(header, timeName); 904 if (! timeItem) { 905 psError(PS_ERR_IO, false, "Unable to find time header: %s\n", 906 timeName); 907 } else if (timeItem->type == PS_DATA_STRING) { 908 // Time is a string, in the usual way: 909 psStringAppend(&dateString, "T%s", timeItem->data.V); 910 } else { 911 // Assume that time is specified in Second of Day 912 double seconds = NAN; 913 switch (timeItem->type) { 914 case PS_TYPE_S32: 915 seconds = timeItem->data.S32; 916 break; 917 case PS_TYPE_F32: 918 seconds = timeItem->data.F32; 919 break; 920 case PS_TYPE_F64: 921 seconds = timeItem->data.F64; 922 break; 923 default: 924 psError(PS_ERR_IO, true, "Time header (%s) is not of an " 925 "expected type: %x\n", timeName, timeItem->type); 926 } 927 // Now print to timeString as "hh:mm:ss.ss" 928 int hours = seconds / 3600; 929 seconds -= (double)hours * 3600.0; 930 int minutes = seconds / 60; 931 seconds -= (double)minutes * 60.0; 932 psStringAppend(&dateString, "T%02d:%02d:%02f", hours, minutes, 933 seconds); 934 } 935 time = psTimeFromISO(dateString, timeSys); 936 } // Reading date and time 937 psFree(timeName); 938 } // Reading headers 939 } else { 940 psError(PS_ERR_IO, true, "Not sure how to parse CELL.TIME (%s) --- trying " 941 "ISO\n", timeString); 942 time = psTimeFromISO(timeString, timeSys); 943 } // Interpreting the time string 944 } 945 break; 946 case PS_TYPE_F32: 947 { 948 double timeValue = (double)timeItem->data.F32; 949 if (strcasecmp(timeFormat, "JD") == 0) { 950 time = psTimeFromJD(timeValue); 951 } else if (strcasecmp(timeFormat, "MJD") == 0) { 952 time = psTimeFromMJD(timeValue); 953 } else { 954 psError(PS_ERR_IO, true, "Not sure how to parse CELL.TIME (%f) --- trying " 955 "JD\n", timeValue); 956 time = psTimeFromJD(timeValue); 957 } 958 } 959 break; 960 case PS_TYPE_F64: 961 { 962 double timeValue = (double)timeItem->data.F64; 963 if (strcasecmp(timeFormat, "JD") == 0) { 964 time = psTimeFromJD(timeValue); 965 } else if (strcasecmp(timeFormat, "MJD") == 0) { 966 time = psTimeFromMJD(timeValue); 967 } else { 968 psError(PS_ERR_IO, true, "Not sure how to parse CELL.TIME (%f) --- trying " 969 "JD\n", timeValue); 970 time = psTimeFromJD(timeValue); 971 } 972 } 973 break; 974 default: 975 psError(PS_ERR_IO, true, "Unable to parse CELL.TIME.\n"); 976 } 977 } else { 978 psError(PS_ERR_IO, false, "Unable to find CELL.TIME in FORMATS.\n"); 979 } // Getting the format 980 } else { 981 psError(PS_ERR_IO, false, "Unable to find FORMATS in camera configuration.\n"); 982 } // Getting the formats 983 } // Getting CELL.TIME 984 985 psMetadataAdd(cell->concepts, PS_LIST_TAIL, "CELL.TIME", PS_DATA_UNKNOWN, "Time of exposure", time); 986 psFree(time); 987 } 988 989 // These are new and experimental concepts: CELL.X0 and CELL.Y0 990 991 // CELL.X0 992 p_pmFPAConceptGetS32(fpa, chip, cell, db, cell->concepts, "CELL.X0", "Position of (0,0) on the chip "); 993 // CELL.Y0 994 p_pmFPAConceptGetS32(fpa, chip, cell, db, cell->concepts, "CELL.Y0", "Position of (0,0) on the chip"); 995 // Add corrective 996 { 997 const psMetadata *camera = fpa->camera; 998 bool mdok = false; // Result of MD lookup 999 psMetadata *formats = psMetadataLookupMD(&mdok, camera, "FORMATS"); 1000 if (mdok && formats) { 1001 psString format = psMetadataLookupString(&mdok, formats, "CELL.X0"); 1002 if (mdok && strlen(format) > 0 && strcasecmp(format, "FORTRAN") == 0) { 1003 psMetadataItem *cellx0 = psMetadataLookup(cell->concepts, "CELL.X0"); 1004 cellx0->data.S32 -= 1; 1005 } 1006 format = psMetadataLookupString(&mdok, formats, "CELL.Y0"); 1007 if (mdok && strlen(format) > 0 && strcasecmp(format, "FORTRAN") == 0) { 1008 psMetadataItem *celly0 = psMetadataLookup(cell->concepts, "CELL.Y0"); 1009 celly0->data.S32 -= 1; 1010 } 1011 } 1012 } 1013 1014 // Pau. 1024 p_pmCellIngestConcept(fpa, chip, cell, db, "CELL.EXPOSURE"); 1025 p_pmCellIngestConcept(fpa, chip, cell, db, "CELL.DARKTIME"); 1026 1027 1028 p_pmCellIngestConcept(fpa, chip, cell, db, "CELL.TRIMSEC"); 1029 p_pmCellIngestConcept(fpa, chip, cell, db, "CELL.BIASSEC"); 1030 p_pmCellIngestConcept(fpa, chip, cell, db, "CELL.TIME"); // This also does CELL.TIMESYS 1031 p_pmCellIngestConcept(fpa, chip, cell, db, "CELL.XBIN"); 1032 p_pmCellIngestConcept(fpa, chip, cell, db, "CELL.YBIN"); 1033 p_pmCellIngestConcept(fpa, chip, cell, db, "CELL.X0"); 1034 p_pmCellIngestConcept(fpa, chip, cell, db, "CELL.Y0"); 1035 1015 1036 } 1016 1037 … … 1018 1039 // Retrieve a concept 1019 1040 psMetadataItem *pmCellGetConcept(pmCell *cell, // The cell 1020 const char *concept // The concept1041 const char *concept // The concept 1021 1042 ) 1022 1043 { 1023 1044 psMetadataItem *item = psMetadataLookup(cell->concepts, concept); 1024 1045 if (! item) { 1025 pmChip *chip = cell->parent;1026 item = psMetadataLookup(chip->concepts, concept);1027 if (! item) {1028 pmFPA *fpa = chip->parent;1029 item = psMetadataLookup(fpa->concepts, concept);1030 }1031 } 1032 return item; // item is either NULL or is what we want.1033 } 1046 pmChip *chip = cell->parent; 1047 item = psMetadataLookup(chip->concepts, concept); 1048 if (! item) { 1049 pmFPA *fpa = chip->parent; 1050 item = psMetadataLookup(fpa->concepts, concept); 1051 } 1052 } 1053 return item; // item is either NULL or is what we want. 1054 }
Note:
See TracChangeset
for help on using the changeset viewer.
