/***************************************************************************** * Johns Hopkins University * Center For Astrophysical Sciences * FUSE ***************************************************************************** * * Synopsis: cf_fuv_init(fitsfile *fptr) * * Description: cf_fuv_init performs the following functions: * 1. Populates the data processing step keywords based upon * the type of data (TTAG or HIST). The processing steps * and the associated keywords are defined in the * structure CALIBRATION_STEP_KEYS in calfuse.h. * 2. Populates the orbital parameters in the header by * calling read_tle. The orbital elements come from * the file FUSE.TLE, which is in standard NORAD two-line * element format. * 3. Populates the calibration file keywords based on the * time and date of observation, the detector segment, * and the interpolation status of the calibration file. * The relation between processing steps and associated * calibration file keywords is defined in the structure * CALIBRATION_FILE_KEYS in calfuse.h. The names and * effective dates of the calibration files are found in * the ASCII-format file master_calib_file.dat in the * CF_PARMDIR directory. * * Input: fitsfile *fptr Pointer to input file * * History: 05/11/98 emm Begin work. * 05/15/98 emm finished * 06/04/98 emm Modified keywords to reflect updated * calfuse design * 11/12/98 emm Added ability to read orbital elements * from file FUSE.TLE. * 03/18/99 emm Added call to cf_cal_file. master_ * calib_file.dat must now be in the * CF_CALDIR directory. (on 08/25/99 * this became CF_PARMDIR). * 03/18/99 emm Edited header only. * 04/14/99 peb Increased strings sizes to prevent * character overflow. * Implemented FITS wrapper functions. * 05/19/99 peb Implemented cf_error_msg functions. * 06/07/99 peb Added reporting of version number. * 07/29/99 emm Added CF_VERS keyword update. * 08/25/99 emm master_calib_file.dat now in CF_PARMDIR * 12/06/99 v1.8 emm Removed cf_if_error call when master * calib file keyword not found. * 10/13/00 v1.9 jwk change CF_VER_NUM from "1.5" * 08/23/01 v1.10 wvd Read PARM file; if requested, set * BRST_COR, ASTG_COR, PHAX_COR, * MKBK_COR, or BKGD_COR to "OMIT" * 10/23/01 v1.11 hsu Check OPUS version * 10/26/01 v1.12 wvd Install subroutine. * 02/11/02 v1.13 wvd Check detector bias levels. * 02/13/02 v1.14 wvd Modified bias logic; write warning * to data header as COMMENT lines. * 02/13/02 v1.15 wvd Don't crash if bias keywords missing. * 02/19/02 v1.16 wvd Check whether voltage too high * 02/20/02 v1.17 wvd If keyword RAWTIME does not exist, * create with value of EXPTIME * 10/30/02 1.18 peb Converted header to calfusettag.h * 03/26/03 1.4 wvd Removed "Warning" from warnings. * 04/16/03 v1.5 wvd Test for corrupted bias values. * Update comment field for HV_FLAG. * 04/28/03 v1.6 wvd Change logic of assigning cal files * never to extrapolate forward in time. * 07/23/03 v1.7 wvd Write HSKP_CAL to file header. * 07/23/03 v1.8 wvd Change calfusettag.h to calfuse.h * 09/09/03 v1.9 wvd Read SAA_SCR and LIMB_SCR from * SCRN_CAL and set RUN_SAA and RUN_LIMB. * 04/27/04 v1.10 wvd Keywords MKBK_COR and BKGD_COR are * gone, so we don't populate them. * 06/04/04 v1.11 wvd Allow for the possibility that the * time associated with a calibration * file exactly equals EXPSTART. * 06/14/04 v1.12 wvd Check value of BRIT_OBJ keyword and * modify header accordingly. * Write CF_VERS to trailer file. * 07/16/04 v1.13 wvd Must set ASTG_COR to PERFORM, as * pipeline doesn't do it automatically. * 11/26/04 v1.14 wvd Check whether SAA_SCR and LIMB_SCR * are ON or OFF, not YES or NO. * 12/02/04 v1.15 wvd Read value of RUN_JITR from PARM file. * 03/24/05 v1.16 wvd Use HVGOODLM to determine whether * detector voltage is low. * 06/12/06 v1.17 wvd Call cf_verbose rather than * cf_if_warning for non-optimal voltage. * 07/18/08 v1.18 wvd For bright-earth and airglow exposures, * change EXP_STAT to 2, * change SRC_TYPE to EE, and * write warning to file header. * ****************************************************************************/ #include #include #include #include "calfuse.h" #define MAXCHARS 120 #define MASTER_CAL_FILE "master_calib_file.dat" int cf_fuv_init(fitsfile *fptr) { char CF_PRGM_ID[] = "cf_fuv_init"; char CF_VER_NUM[] = "1.18"; int i, status=0, expstat, interp_in, timeref; int n, hv_flag, lowv, highv, saav, fullv; char comment[FLEN_CARD], instmode[FLEN_CARD], detector[FLEN_CARD]; char opus_str[FLEN_CARD], keyword_in[FLEN_CARD], segment_in[FLEN_CARD]; char datestr[FLEN_CARD]; char filename_in[]=" ", rootname[FLEN_CARD]; char hkexists[FLEN_CARD]; char keyword_out1[FLEN_CARD], keyword_out2[FLEN_CARD]; char linin[MAXCHARS]; char run_limb[FLEN_VALUE], run_saa[FLEN_VALUE], src_type[FLEN_VALUE]; char run_brst[FLEN_VALUE], run_walk[FLEN_VALUE], run_astg[FLEN_VALUE]; /* char run_mkbk[FLEN_VALUE], run_bkgd[FLEN_VALUE], brit_obj[FLEN_VALUE]; */ char run_jitr[FLEN_VALUE], brit_obj[FLEN_VALUE]; char hv_str[FLEN_CARD], lv_str[FLEN_CARD], mjd_str[FLEN_CARD]; char saa_str[FLEN_CARD], full_str[FLEN_CARD]; float hvgood, mjdv, expstart, aftermjd_in; fitsfile *parmfits, *scrnfits; struct keyword_tab keytab[NUM_PROC_STEPS]=CALIBRATION_STEP_KEYS; struct cal_file_tab calkey[NUMCALKEYS]=CALIBRATION_FILE_KEYS; FILE *fpin; cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Begin initializing headers"); /* Check the OPUS version number */ fits_read_key(fptr, TSTRING, "OPUSVERS", opus_str, NULL, &status); if (status) { status = 0; cf_add_header_keywords(fptr); cf_verbose(2, "Data file generated by old version of OPUS."); } else if (atof(opus_str) < OPUS_VERSION) { cf_add_header_keywords(fptr); cf_verbose(2, "Data file generated by old version (%s) of OPUS.", opus_str); } FITS_update_key(fptr, TSTRING, "CF_VERS", CALFUSE_VERSION, NULL, &status); cf_verbose (1, "This is CalFUSE v%s", CALFUSE_VERSION); /* * Populate data processing keywords based on observing mode found * in the INSTMODE keyword. NOTE: We check only the first * letter of the INSTMODE keyword. */ FITS_read_key(fptr, TSTRING, "INSTMODE", instmode, NULL, &status); switch (instmode[0]) { case 'H': /* Histogram mode */ for (i=0; i second cal file preceeding observation * calkey[i].filenames[1] => cal file immediately preceeding observa- * tion * calkey[i].filenames[2] => cal file immediately after observation * * Here is the plan. Cycle through the master cal file, reading each * line. Determine the keyword for each line, and use that to determine * the appropriate index [i] for calkey. Then, if the detector segment * is correct, determine where the new file fits into the structure above. * If it is more recent than one or both of the preceeding cal files, * but is older than the observation (expstart) replace either * filenames[0] or filenames[1]. If filenames[1] is replaced, shift * the old value down into filenames[0]. If the file is more recent * than the observation, and closer to the observation than the file * in filenames[2], replace filenames[2]. The values * calkey[i].aftermjd[] and calkey[i].interp[] store the date and * interpolation status of the best files. This organization allows * the master calibration database file to be written in any order. */ while (fgets(linin, MAXCHARS, fpin) != NULL) { /* Check for comment lines */ if ((linin[0] != '#') && (linin[0] != '\n')) { sscanf(linin, "%4c%*2c%2c%*2c%13c%*2c%9f%*2c%1d",keyword_in, segment_in,filename_in,&aftermjd_in,&interp_in); /* * Determine which keyword we just read in. */ i=0; while ((strncmp(calkey[i].name,keyword_in,4) != 0) && (i < NUMCALKEYS)) i++; if (i >= NUMCALKEYS) { cf_if_warning("Keyword %s in %s is unknown", keyword_in, MASTER_CAL_FILE); } else { if ((strncmp(segment_in," ",2) == 0) || (strncmp(segment_in,detector,2) == 0)) { if ((aftermjd_in <= expstart) && (aftermjd_in > calkey[i].aftermjd[0]) && (aftermjd_in > calkey[i].aftermjd[1])) { strncpy(calkey[i].filenames[0], calkey[i].filenames[1],18); calkey[i].aftermjd[0]=calkey[i].aftermjd[1]; calkey[i].interp[0]=calkey[i].interp[1]; strncpy(calkey[i].filenames[1], filename_in,18); calkey[i].aftermjd[1]=aftermjd_in; calkey[i].interp[1]=interp_in; } else if ((aftermjd_in < expstart) && (aftermjd_in > calkey[i].aftermjd[0])) { strncpy(calkey[i].filenames[0], filename_in,18); calkey[i].aftermjd[0]=aftermjd_in; calkey[i].interp[0]=interp_in; } if ((aftermjd_in > expstart) && (aftermjd_in < calkey[i].aftermjd[2])) { strncpy(calkey[i].filenames[2], filename_in,18); calkey[i].aftermjd[2]=aftermjd_in; calkey[i].interp[2]=interp_in; } } /* Endif segment match */ } /* end else unrecognized keyword */ } /* end while linin not comment */ } /* end while(linin != NULL) */ fclose(fpin); /************************************************************************* I have changed Rule 3 so that we NEVER extrapolate calibration files forward in time. Instead, we just use the most recent file. This reduces from 8 to 4 the number of possible cases, since we no longer care about the value of interp[0]. This section and the previous one ought to be re-written, but I will simply change 0 to 1 for Case 110 below. WVD - 04/28/03 *************************************************************************/ /* OK, now that we have identified the closest two files before * the observation, and the file after the observation, we can * decide what to do with them. First, the easy part: if * calkey[i].numfiles=1, no interpolation is possible, so we * write out calkey[i].filenames[1], which is the file immediately * preceeding the observation. If calkey[i].numfiles=2, interpolation * is possible, and we will have to write two keywords into the header. * The decision as to which two keywords to write follows these rules: * Rule 1: If an observation occurs between two files which can be * interpolated, then an interpolation must be done. * Rule 2: If the calibration file immediately preceeding an * observation is to be used in a stepwise manner, then said * file shall be used in stepwise manner. * Rule 3: If the two calibration files immediately preceeding an * observation can be interpolated, but the following file * cannot, then the two previous files will be extrapolated * forward in time. * Rule 4: If the closest preceeding calibration file has an interpolation * flag, but the file preceeding it has a stepwise flag, the the * closest preceeding file will be used in a sterpwise manner. * Rule 5: Never interpolate backward in time. * * In fact, there are only 8 possible cases: * * Remember, the files were sorted such that the observation * always occurs between [1] and [2]. Also remember that * interp[i]=0 => stepwise): * * Case Action * * interp[0] = 0 * interp[1] = 0 filenames[1] will be used in a stepwise manner * interp[2] = 0 * * interp[0] = 0 * interp[1] = 0 filenames[1] will be used in a stepwise manner * interp[2] = 1 * * interp[0] = 0 * interp[1] = 1 filenames[1] will be used in a stepwise manner * interp[2] = 0 * * interp[0] = 1 * interp[1] = 0 filenames[1] will be used in a stepwise manner * interp[2] = 0 * * interp[0] = 1 * interp[1] = 0 filenames[1] will be used in a stepwise manner * interp[2] = 1 * * interp[0] = 0 * interp[1] = 1 filenames[1] and filenames[2] will be interpolated * interp[2] = 1 * * interp[0] = 1 * interp[1] = 1 filenames[0] and filenames[1] will be extrapolated * interp[2] = 0 * * interp[0] = 1 * interp[1] = 1 filenames[1] and filenames[2] will be interpolated * interp[2] = 1 * */ /* Write the calibration files into the header keywords. */ /* Cycle through the keywords. */ for (i=0; i mjdv); n--; sprintf(saa_str, "SAA%d", n); sprintf(full_str, "FULL%d", n); FITS_read_key(parmfits, TINT, saa_str, &saav, NULL, &status); FITS_read_key(parmfits, TINT, full_str, &fullv, NULL, &status); FITS_close_file(parmfits, &status); if (lowv > fullv + 3) { hv_flag = 5; sprintf(comment, "Detector voltage high throughout exposure"); } else if ((float) lowv / fullv > hvgood) { hv_flag = 4; sprintf(comment, "Detector voltage full throughout exposure"); } else if (lowv > saav + 3) { hv_flag = 3; sprintf(comment, "Detector voltage low throughout exposure"); } else if (lowv > saav - 3) { hv_flag = 2; sprintf(comment, "Detector at SAA voltage throughout exposure"); } else { hv_flag = 1; sprintf(comment, "Detector below SAA voltage throughout exposure"); } if (highv - lowv > 3) { hv_flag = 0; sprintf (comment, "Detector voltage changed during exposure"); } else if (lowv > highv) { hv_flag = -1; sprintf(comment, "Detector bias keywords are corrupted"); } FITS_update_key(fptr, TINT, "HV_FLAG", &hv_flag, comment, &status); if (hv_flag != 4) { if (hv_flag == -1) cf_if_warning(comment); else cf_verbose(1, comment); FITS_write_comment(fptr, " ", &status); FITS_write_comment(fptr, comment, &status); fits_get_system_time(datestr, &timeref, &status); sprintf(comment, "CalFUSE v%s %.10s", CALFUSE_VERSION, datestr); FITS_write_comment(fptr, comment, &status); FITS_write_comment(fptr, " ", &status); } } /* Read BRIT_OBS keyword and modify header accordingly. */ FITS_read_key(fptr, TSTRING, "SRC_TYPE", src_type, NULL, &status); FITS_read_key(fptr, TSTRING, "BRIT_OBJ", brit_obj, NULL, &status); if (!strcmp(brit_obj, "DEFOCUS") && !strncmp(src_type, "P", 1)) { *src_type = 'E'; FITS_update_key(fptr, TSTRING, "SRC_TYPE", src_type, "DEFOCUS OBS ==> Treat as extended source", &status); } /* Flag bright-earth and airglow (M106, S100, and 900+) exposures. */ FITS_read_key(fptr, TSTRING, "ROOTNAME", rootname, NULL, &status); if (!strncmp(rootname, "M106", 4) || !strncmp(rootname, "S100", 4)) { cf_verbose(1, "Bright-earth exposure."); /* Set EXP_STAT to TEMPORAL_LIMB. */ expstat = (int) TEMPORAL_LIMB; FITS_update_key(fptr, TINT, "EXP_STAT", &expstat, "Bright-earth exposure", &status); } if (!strncmp(rootname+8, "9", 1)) { cf_verbose(1, "Airglow exposure. Will treat as extended source."); /* Set EXP_STAT to TEMPORAL_LIMB. */ expstat = (int) TEMPORAL_LIMB; FITS_update_key(fptr, TINT, "EXP_STAT", &expstat, "Airglow exposure", &status); /* Change SRC_TYPE to EE. */ (void) strcpy(src_type, "EE"); FITS_update_key(fptr, TSTRING, "SRC_TYPE", src_type, "Airglow exposure ==> Treat as extended source", &status); /* Write warning to trailer file and IDF header. */ FITS_write_comment(fptr, " ", &status); sprintf(comment, "Airglow exposure. Not an astrophysical target."); FITS_write_comment(fptr, comment, &status); fits_get_system_time(datestr, &timeref, &status); sprintf(comment, "CalFUSE v%s %.10s", CALFUSE_VERSION, datestr); FITS_write_comment(fptr, comment, &status); FITS_write_comment(fptr, " ", &status); } /* Read the SCRN file and see if user wants to skip any steps. */ FITS_read_key(fptr, TSTRING, "SCRN_CAL", filename_in, NULL, &status); FITS_open_file(&scrnfits, cf_parm_file(filename_in), READONLY, &status); FITS_read_key(scrnfits, TSTRING, "SAA_SCR", run_saa, NULL, &status); FITS_read_key(scrnfits, TSTRING, "LIMB_SCR", run_limb, NULL, &status); FITS_close_file(scrnfits, &status); /* Now read the PARM file and see if user wants to skip any steps. */ FITS_read_key(fptr, TSTRING, "PARM_CAL", filename_in, NULL, &status); FITS_open_file(&parmfits, cf_parm_file(filename_in), READONLY, &status); FITS_read_key(parmfits, TSTRING, "RUN_BRST", run_brst, NULL, &status); FITS_read_key(parmfits, TSTRING, "RUN_PHAX", run_walk, NULL, &status); /* FITS_read_key(parmfits, TSTRING, "RUN_MKBK", run_mkbk, NULL, &status); */ /* FITS_read_key(parmfits, TSTRING, "RUN_BKGD", run_bkgd, NULL, &status); */ FITS_read_key(parmfits, TSTRING, "RUN_ASTG", run_astg, NULL, &status); FITS_read_key(parmfits, TSTRING, "RUN_JITR", run_jitr, NULL, &status); FITS_close_file(parmfits, &status); if (!strncmp(run_limb, "OFF", 3) || !strncmp(run_limb, "off", 3)) FITS_update_key(fptr, TSTRING, "LIMB_COR", "OMIT", NULL, &status); if (!strncmp(run_saa, "OFF", 3) || !strncmp(run_saa, "off", 3)) FITS_update_key(fptr, TSTRING, "SAA__COR", "OMIT", NULL, &status); if (!strncmp(run_brst, "N", 1) || !strncmp(run_brst, "n", 1)) FITS_update_key(fptr, TSTRING, "BRST_COR", "OMIT", NULL, &status); if (!strncmp(run_walk, "N", 1) || !strncmp(run_walk, "n", 1)) FITS_update_key(fptr, TSTRING, "PHAX_COR", "OMIT", NULL, &status); /* if (!strncmp(run_mkbk, "N", 1) || !strncmp(run_mkbk, "n", 1)) FITS_update_key(fptr, TSTRING, "MKBK_COR", "OMIT", NULL, &status); if (!strncmp(run_bkgd, "N", 1) || !strncmp(run_bkgd, "n", 1)) FITS_update_key(fptr, TSTRING, "BKGD_COR", "OMIT", NULL, &status); */ if (!strncmp(run_astg, "N", 1) || !strncmp(run_astg, "n", 1)) FITS_update_key(fptr, TSTRING, "ASTG_COR", "OMIT", NULL, &status); else FITS_update_key(fptr, TSTRING, "ASTG_COR", "PERFORM", NULL, &status); if (!strncmp(run_jitr, "N", 1) || !strncmp(run_jitr, "n", 1)) FITS_update_key(fptr, TSTRING, "JITR_COR", "OMIT", NULL, &status); else FITS_update_key(fptr, TSTRING, "JITR_COR", "PERFORM", NULL, &status); cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Done initializing headers"); return status; }