From d54fe7c1f704a63824c5bfa0ece65245572e9b27 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Wed, 4 Mar 2015 21:21:30 -0500 Subject: Initial commit --- src/libcf/Makefile.Linux.orig | 152 +++ src/libcf/Makefile.Linux64.orig | 151 +++ src/libcf/Makefile.MacOSX.orig | 152 +++ src/libcf/Makefile.Solaris.orig | 152 +++ src/libcf/Makefile.orig.orig | 152 +++ src/libcf/calfits.c | 658 ++++++++++++ src/libcf/cf_active_region.c | 90 ++ src/libcf/cf_apply_dead_time.c | 142 +++ src/libcf/cf_apply_filters.c | 177 ++++ src/libcf/cf_astig_farf.c | 144 +++ src/libcf/cf_astigmatism.c | 198 ++++ src/libcf/cf_cal_file.c | 84 ++ src/libcf/cf_calculate_y_centroid.c | 289 ++++++ src/libcf/cf_calculate_ycent_motion.c | 152 +++ src/libcf/cf_check_digitizer.c | 101 ++ src/libcf/cf_convert_to_ergs.c | 182 ++++ src/libcf/cf_count_rate_y_distort.c | 157 +++ src/libcf/cf_dispersion.c | 85 ++ src/libcf/cf_doppler_and_heliocentric.c | 87 ++ src/libcf/cf_electronics_dead_time.c | 104 ++ src/libcf/cf_error_msg.c | 263 +++++ src/libcf/cf_extraction_limits.c | 137 +++ src/libcf/cf_fes_proc_check.c | 94 ++ src/libcf/cf_fes_proc_update.c | 68 ++ src/libcf/cf_fifo_dead_time.c | 164 +++ src/libcf/cf_find_spectra.c | 396 ++++++++ src/libcf/cf_fpa_position.c | 231 +++++ src/libcf/cf_fuv_init.c | 592 +++++++++++ src/libcf/cf_geometric_distort.c | 145 +++ src/libcf/cf_grating_motion.c | 432 ++++++++ src/libcf/cf_header_io.c | 110 ++ src/libcf/cf_identify_channel.c | 201 ++++ src/libcf/cf_idf_io.c | 161 +++ src/libcf/cf_ids_dead_time.c | 109 ++ src/libcf/cf_init_support.c | 1344 +++++++++++++++++++++++++ src/libcf/cf_make_mask.c | 175 ++++ src/libcf/cf_make_wave_array.c | 147 +++ src/libcf/cf_mirror_motion.c | 189 ++++ src/libcf/cf_modify_hist_pha.c | 91 ++ src/libcf/cf_modify_hist_times.c | 83 ++ src/libcf/cf_nint.c | 47 + src/libcf/cf_optimal_extraction.c | 551 ++++++++++ src/libcf/cf_pha_x_distort.c | 107 ++ src/libcf/cf_proc_check.c | 124 +++ src/libcf/cf_proc_update.c | 97 ++ src/libcf/cf_read_fpa_pos.c | 82 ++ src/libcf/cf_rebin_background.c | 211 ++++ src/libcf/cf_rebin_probability_array.c | 180 ++++ src/libcf/cf_satellite_jitter.c | 245 +++++ src/libcf/cf_scale_bkgd.c | 956 ++++++++++++++++++ src/libcf/cf_screen_airglow.c | 70 ++ src/libcf/cf_screen_bad_pixels.c | 122 +++ src/libcf/cf_screen_burst.c | 758 ++++++++++++++ src/libcf/cf_screen_high_voltage.c | 146 +++ src/libcf/cf_screen_jitter.c | 246 +++++ src/libcf/cf_screen_limb_angle.c | 87 ++ src/libcf/cf_screen_pulse_height.c | 79 ++ src/libcf/cf_screen_saa.c | 83 ++ src/libcf/cf_set_good_time_intervals.c | 157 +++ src/libcf/cf_set_photon_flags.c | 425 ++++++++ src/libcf/cf_set_user_gtis.c | 100 ++ src/libcf/cf_source_aper.c | 67 ++ src/libcf/cf_standard_or_optimal_extraction.c | 75 ++ src/libcf/cf_target_count_rate.c | 112 +++ src/libcf/cf_thermal_distort.c | 258 +++++ src/libcf/cf_time_xy_distort.c | 171 ++++ src/libcf/cf_timestamp.c | 78 ++ src/libcf/cf_velang.c | 147 +++ src/libcf/cf_write_extracted_spectrum.c | 226 +++++ src/libcf/eclipse.c | 148 +++ src/libcf/geod_mag.c | 40 + src/libcf/helio_vel.c | 82 ++ src/libcf/lsrd_vel.c | 51 + src/libcf/lsrk_vel.c | 52 + src/libcf/month_day.c | 19 + src/libcf/pole_ang.c | 64 ++ src/libcf/read_tle.c | 303 ++++++ src/libcf/saa.c | 74 ++ src/libcf/set_orbit_parms.c | 86 ++ src/libcf/sgp4.c | 426 ++++++++ src/libcf/solar_ang.c | 90 ++ src/libcf/space_vel.c | 46 + src/libcf/state_geod.c | 107 ++ src/libcf/state_limb.c | 159 +++ 84 files changed, 16295 insertions(+) create mode 100644 src/libcf/Makefile.Linux.orig create mode 100644 src/libcf/Makefile.Linux64.orig create mode 100644 src/libcf/Makefile.MacOSX.orig create mode 100644 src/libcf/Makefile.Solaris.orig create mode 100644 src/libcf/Makefile.orig.orig create mode 100644 src/libcf/calfits.c create mode 100644 src/libcf/cf_active_region.c create mode 100644 src/libcf/cf_apply_dead_time.c create mode 100644 src/libcf/cf_apply_filters.c create mode 100644 src/libcf/cf_astig_farf.c create mode 100644 src/libcf/cf_astigmatism.c create mode 100644 src/libcf/cf_cal_file.c create mode 100644 src/libcf/cf_calculate_y_centroid.c create mode 100644 src/libcf/cf_calculate_ycent_motion.c create mode 100644 src/libcf/cf_check_digitizer.c create mode 100644 src/libcf/cf_convert_to_ergs.c create mode 100644 src/libcf/cf_count_rate_y_distort.c create mode 100644 src/libcf/cf_dispersion.c create mode 100644 src/libcf/cf_doppler_and_heliocentric.c create mode 100644 src/libcf/cf_electronics_dead_time.c create mode 100644 src/libcf/cf_error_msg.c create mode 100644 src/libcf/cf_extraction_limits.c create mode 100644 src/libcf/cf_fes_proc_check.c create mode 100644 src/libcf/cf_fes_proc_update.c create mode 100644 src/libcf/cf_fifo_dead_time.c create mode 100644 src/libcf/cf_find_spectra.c create mode 100644 src/libcf/cf_fpa_position.c create mode 100644 src/libcf/cf_fuv_init.c create mode 100644 src/libcf/cf_geometric_distort.c create mode 100644 src/libcf/cf_grating_motion.c create mode 100644 src/libcf/cf_header_io.c create mode 100644 src/libcf/cf_identify_channel.c create mode 100644 src/libcf/cf_idf_io.c create mode 100644 src/libcf/cf_ids_dead_time.c create mode 100644 src/libcf/cf_init_support.c create mode 100644 src/libcf/cf_make_mask.c create mode 100644 src/libcf/cf_make_wave_array.c create mode 100644 src/libcf/cf_mirror_motion.c create mode 100644 src/libcf/cf_modify_hist_pha.c create mode 100644 src/libcf/cf_modify_hist_times.c create mode 100644 src/libcf/cf_nint.c create mode 100644 src/libcf/cf_optimal_extraction.c create mode 100644 src/libcf/cf_pha_x_distort.c create mode 100644 src/libcf/cf_proc_check.c create mode 100644 src/libcf/cf_proc_update.c create mode 100644 src/libcf/cf_read_fpa_pos.c create mode 100644 src/libcf/cf_rebin_background.c create mode 100644 src/libcf/cf_rebin_probability_array.c create mode 100644 src/libcf/cf_satellite_jitter.c create mode 100644 src/libcf/cf_scale_bkgd.c create mode 100644 src/libcf/cf_screen_airglow.c create mode 100644 src/libcf/cf_screen_bad_pixels.c create mode 100644 src/libcf/cf_screen_burst.c create mode 100644 src/libcf/cf_screen_high_voltage.c create mode 100644 src/libcf/cf_screen_jitter.c create mode 100644 src/libcf/cf_screen_limb_angle.c create mode 100644 src/libcf/cf_screen_pulse_height.c create mode 100644 src/libcf/cf_screen_saa.c create mode 100644 src/libcf/cf_set_good_time_intervals.c create mode 100644 src/libcf/cf_set_photon_flags.c create mode 100644 src/libcf/cf_set_user_gtis.c create mode 100644 src/libcf/cf_source_aper.c create mode 100644 src/libcf/cf_standard_or_optimal_extraction.c create mode 100644 src/libcf/cf_target_count_rate.c create mode 100644 src/libcf/cf_thermal_distort.c create mode 100644 src/libcf/cf_time_xy_distort.c create mode 100644 src/libcf/cf_timestamp.c create mode 100644 src/libcf/cf_velang.c create mode 100644 src/libcf/cf_write_extracted_spectrum.c create mode 100644 src/libcf/eclipse.c create mode 100644 src/libcf/geod_mag.c create mode 100644 src/libcf/helio_vel.c create mode 100644 src/libcf/lsrd_vel.c create mode 100644 src/libcf/lsrk_vel.c create mode 100644 src/libcf/month_day.c create mode 100644 src/libcf/pole_ang.c create mode 100644 src/libcf/read_tle.c create mode 100644 src/libcf/saa.c create mode 100644 src/libcf/set_orbit_parms.c create mode 100644 src/libcf/sgp4.c create mode 100644 src/libcf/solar_ang.c create mode 100644 src/libcf/space_vel.c create mode 100644 src/libcf/state_geod.c create mode 100644 src/libcf/state_limb.c (limited to 'src/libcf') diff --git a/src/libcf/Makefile.Linux.orig b/src/libcf/Makefile.Linux.orig new file mode 100644 index 0000000..43b2e31 --- /dev/null +++ b/src/libcf/Makefile.Linux.orig @@ -0,0 +1,152 @@ +LIBRARY= libcf + +CALFUSEDIR= ${PWD}/../.. +SHARED= -shared +FITSVER= 2.470 + +# Symbols for include directories +FUSEINCLDIR= -I${CALFUSEDIR}/include + +# Symbols used for compiling +CC= cc +OPT= -g -Wall -DCFORTRAN -Dg77Fortran -Df2cFortran +CFLAGS= ${OPT} ${FUSEINCLDIR} + +FUSELIBDIR= -L${CALFUSEDIR}/lib +FUSELIBS= -lcfitsio-${FITSVER} -lsla +LIBS= -lc -lm -lnsl -ldl -lgfortran +LDFLAGS= + +# Symbols used for creating shared libraries + +SO= .so + +OBJS= calfits.o sgp4.o eclipse.o saa.o \ + state_limb.o state_geod.o space_vel.o helio_vel.o \ + geod_mag.o pole_ang.o solar_ang.o lsrd_vel.o lsrk_vel.o \ + month_day.o read_tle.o cf_velang.o \ + set_orbit_parms.o cf_error_msg.o \ + cf_cal_file.o cf_proc_check.o cf_proc_update.o \ + cf_timestamp.o cf_fuv_init.o cf_header_io.o \ + cf_check_digitizer.o cf_nint.o \ + cf_idf_io.o cf_ids_dead_time.o cf_electronics_dead_time.o \ + cf_fifo_dead_time.o cf_apply_dead_time.o \ + cf_thermal_distort.o cf_count_rate_y_distort.o cf_time_xy_distort.o \ + cf_geometric_distort.o cf_pha_x_distort.o \ + cf_active_region.o cf_find_spectra.o cf_identify_channel.o \ + cf_calculate_ycent_motion.o cf_source_aper.o\ + cf_grating_motion.o cf_fpa_position.o cf_read_fpa_pos.o \ + cf_make_mask.o cf_mirror_motion.o \ + cf_satellite_jitter.o cf_calculate_y_centroid.o \ + cf_target_count_rate.o \ + cf_screen_jitter.o cf_screen_limb_angle.o cf_screen_saa.o \ + cf_screen_high_voltage.o cf_screen_burst.o cf_screen_airglow.o \ + cf_screen_bad_pixels.o cf_set_user_gtis.o \ + cf_set_photon_flags.o cf_set_good_time_intervals.o \ + cf_modify_hist_times.o cf_screen_pulse_height.o \ + cf_convert_to_ergs.o cf_extraction_limits.o \ + cf_astigmatism.o cf_dispersion.o cf_doppler_and_heliocentric.o \ + cf_apply_filters.o cf_scale_bkgd.o \ + cf_make_wave_array.o cf_rebin_background.o \ + cf_rebin_probability_array.o cf_optimal_extraction.o \ + cf_write_extracted_spectrum.o cf_standard_or_optimal_extraction.o \ + cf_init_support.o cf_modify_hist_pha.o \ + cf_fes_proc_check.o cf_fes_proc_update.o + +all: ${OBJS} + ${CC} ${SHARED} -o ${LIBRARY}${SO} ${OBJS} \ + ${FUSELIBDIR} ${FUSELIBS} ${LIBS} ${LDFLAGS} + +install: all + chmod g+w ${OBJS} ${LIBRARY}${SO} + /bin/cp -p ${LIBRARY}${SO} ${CALFUSEDIR}/lib/${LIBRARY}${SO} + +clean: + - /bin/rm -f *.o ${LIBRARY}${SO} ${LIBRARY}${O} + +distclean: + - /bin/rm -f *.o ${LIBRARY}${SO} ${LIBRARY}${O} + cd ../../lib; /bin/rm -f ${LIBRARY}${SO} + +calfits.o: calfits.c +sgp4.o: sgp4.c +eclipse.o: eclipse.c +set_orbit_parms.o: set_orbit_parms.c +saa.o: saa.c +state_limb.o: state_limb.c +state_geod.o: state_geod.c +space_vel.o: space_vel.c +helio_vel.o: helio_vel.c +geod_mag.o: geod_mag.c +pole_ang.o: pole_ang.c +solar_ang.o: solar_ang.c +lsrd_vel.o: lsrd_vel.c +lsrk_vel.o: lsrk_vel.c +month_day.o: month_day.c +read_tle.o: read_tle.c + +cf_error_msg.o: cf_error_msg.c +cf_cal_file.o: cf_cal_file.c +cf_fes_proc_check.o: cf_fes_proc_check.c +cf_fes_proc_update.o: cf_fes_proc_update.c +cf_proc_check.o: cf_proc_check.c +cf_proc_update.o: cf_proc_update.c +cf_fuv_init.o: cf_fuv_init.c +cf_velang.o: cf_velang.c +cf_timestamp.o: cf_timestamp.c + +cf_header_io.o: cf_header_io.c +cf_check_digitizer.o: cf_check_digitizer.c +cf_nint.o: cf_nint.c +cf_idf_io.o: cf_idf_io.c +cf_ids_dead_time.o: cf_ids_dead_time.c +cf_electronics_dead_time.o: cf_electronics_dead_time.c +cf_fifo_dead_time.o: cf_fifo_dead_time.c +cf_apply_dead_time.o: cf_apply_dead_time.c +cf_thermal_distort.o: cf_thermal_distort.c +cf_count_rate_y_distort.o: cf_count_rate_y_distort.c +cf_time_xy_distort.o : cf_time_xy_distort.c +cf_geometric_distort: cf_geometric_distort.c +cf_pha_x_distort.o: cf_pha_x_distort.c +cf_active_region.o: cf_active_region.c +cf_find_spectra.o: cf_find_spectra.c +cf_identify_channel.o: cf_identify_channel.c +cf_init_support.o: cf_init_support.c +cf_target_count_rate.o: cf_target_count_rate.c +cf_calculate_ycent_motion.o: cf_calculate_ycent_motion.c +cf_source_aper.o: cf_source_aper.c +cf_grating_motion.o: cf_grating_motion.c +cf_fpa_position.o: cf_fpa_position.c +cf_read_fpa_pos.o: cf_read_fpa_pos.c +cf_make_mask.o: cf_make_mask.c +cf_mirror_motion.o: cf_mirror_motion.c +cf_satellite_jitter.o: cf_satellite_jitter.c +cf_calculate_y_centroid.o: cf_calculate_y_centroid.c +cf_screen_airglow.o: cf_screen_airglow.c +cf_screen_bad_pixels.o: cf_screen_bad_pixels.c +cf_screen_jitter.o: cf_screen_jitter.c +cf_screen_limb_angle.o: cf_screen_limb_angle.c +cf_screen_saa.o: cf_screen_saa.c +cf_screen_high_voltage.o: cf_screen_high_voltage.c +cf_screen_burst.o: cf_screen_burst.c +cf_set_user_gtis.o: cf_set_user_gtis.c +cf_set_photon_flags.o: cf_set_photon_flags.c +cf_set_good_time_intervals.o: cf_set_good_time_intervals.c +cf_modify_hist_pha.o: cf_modify_hist_pha.c +cf_modify_hist_times.o: cf_modify_hist_times.c +cf_screen_pulse_height.o: cf_screen_pulse_height.c +cf_convert_to_ergs.o: cf_convert_to_ergs.c +cf_extraction_limits.o: cf_extraction_limits.c +cf_astigmatism.o: cf_astigmatism.c +cf_dispersion.o: cf_dispersion.c +cf_doppler_and_heliocentric.o: cf_doppler_and_heliocentric.c +cf_apply_filters.o: cf_apply_filters.c +cf_scale_bkgd.o: cf_scale_bkgd.c +cf_make_mask.o: cf_make_mask.c +cf_make_wave_array.o: cf_make_wave_array.c +cf_rebin_background.o: cf_rebin_background.c +cf_rebin_probability_array.o: cf_rebin_probability_array.c +cf_standard_or_optimal_extraction.o: cf_standard_or_optimal_extraction.c +cf_optimal_extraction.o: cf_optimal_extraction.c +cf_write_extracted_spectrum.o: cf_write_extracted_spectrum.c + diff --git a/src/libcf/Makefile.Linux64.orig b/src/libcf/Makefile.Linux64.orig new file mode 100644 index 0000000..3b00b44 --- /dev/null +++ b/src/libcf/Makefile.Linux64.orig @@ -0,0 +1,151 @@ +LIBRARY= libcf + +CALFUSEDIR= ${PWD}/../.. +SHARED= -shared -fPIC + +# Symbols for include directories +FUSEINCLDIR= -I${CALFUSEDIR}/include + +# Symbols used for compiling +CC= cc +OPT= -g -Wall -DCFORTRAN -Dg77Fortran -Df2cFortran +CFLAGS= ${OPT} ${FUSEINCLDIR} + +FUSELIBDIR= -L${CALFUSEDIR}/lib +FUSELIBS= -lsla +LIBS= -lc -lm -lnsl -ldl -lgfortran -lcfitsio +LDFLAGS= + +# Symbols used for creating shared libraries + +SO= .so + +OBJS= calfits.o sgp4.o eclipse.o saa.o \ + state_limb.o state_geod.o space_vel.o helio_vel.o \ + geod_mag.o pole_ang.o solar_ang.o lsrd_vel.o lsrk_vel.o \ + month_day.o read_tle.o cf_velang.o \ + set_orbit_parms.o cf_error_msg.o \ + cf_cal_file.o cf_proc_check.o cf_proc_update.o \ + cf_timestamp.o cf_fuv_init.o cf_header_io.o \ + cf_check_digitizer.o cf_nint.o \ + cf_idf_io.o cf_ids_dead_time.o cf_electronics_dead_time.o \ + cf_fifo_dead_time.o cf_apply_dead_time.o \ + cf_thermal_distort.o cf_count_rate_y_distort.o cf_time_xy_distort.o \ + cf_geometric_distort.o cf_pha_x_distort.o \ + cf_active_region.o cf_find_spectra.o cf_identify_channel.o \ + cf_calculate_ycent_motion.o cf_source_aper.o\ + cf_grating_motion.o cf_fpa_position.o cf_read_fpa_pos.o \ + cf_make_mask.o cf_mirror_motion.o \ + cf_satellite_jitter.o cf_calculate_y_centroid.o \ + cf_target_count_rate.o \ + cf_screen_jitter.o cf_screen_limb_angle.o cf_screen_saa.o \ + cf_screen_high_voltage.o cf_screen_burst.o cf_screen_airglow.o \ + cf_screen_bad_pixels.o cf_set_user_gtis.o \ + cf_set_photon_flags.o cf_set_good_time_intervals.o \ + cf_modify_hist_times.o cf_screen_pulse_height.o \ + cf_convert_to_ergs.o cf_extraction_limits.o \ + cf_astigmatism.o cf_dispersion.o cf_doppler_and_heliocentric.o \ + cf_apply_filters.o cf_scale_bkgd.o \ + cf_make_wave_array.o cf_rebin_background.o \ + cf_rebin_probability_array.o cf_optimal_extraction.o \ + cf_write_extracted_spectrum.o cf_standard_or_optimal_extraction.o \ + cf_init_support.o cf_modify_hist_pha.o \ + cf_fes_proc_check.o cf_fes_proc_update.o + +all: ${OBJS} + ${CC} ${SHARED} -o ${LIBRARY}${SO} ${OBJS} \ + ${FUSELIBDIR} ${FUSELIBS} ${LIBS} ${LDFLAGS} + +install: all + chmod g+w ${OBJS} ${LIBRARY}${SO} + /bin/cp -p ${LIBRARY}${SO} ${CALFUSEDIR}/lib/${LIBRARY}${SO} + +clean: + - /bin/rm -f *.o ${LIBRARY}${SO} ${LIBRARY}${O} + +distclean: + - /bin/rm -f *.o ${LIBRARY}${SO} ${LIBRARY}${O} + cd ../../lib; /bin/rm -f ${LIBRARY}${SO} + +calfits.o: calfits.c +sgp4.o: sgp4.c +eclipse.o: eclipse.c +set_orbit_parms.o: set_orbit_parms.c +saa.o: saa.c +state_limb.o: state_limb.c +state_geod.o: state_geod.c +space_vel.o: space_vel.c +helio_vel.o: helio_vel.c +geod_mag.o: geod_mag.c +pole_ang.o: pole_ang.c +solar_ang.o: solar_ang.c +lsrd_vel.o: lsrd_vel.c +lsrk_vel.o: lsrk_vel.c +month_day.o: month_day.c +read_tle.o: read_tle.c + +cf_error_msg.o: cf_error_msg.c +cf_cal_file.o: cf_cal_file.c +cf_fes_proc_check.o: cf_fes_proc_check.c +cf_fes_proc_update.o: cf_fes_proc_update.c +cf_proc_check.o: cf_proc_check.c +cf_proc_update.o: cf_proc_update.c +cf_fuv_init.o: cf_fuv_init.c +cf_velang.o: cf_velang.c +cf_timestamp.o: cf_timestamp.c + +cf_header_io.o: cf_header_io.c +cf_check_digitizer.o: cf_check_digitizer.c +cf_nint.o: cf_nint.c +cf_idf_io.o: cf_idf_io.c +cf_ids_dead_time.o: cf_ids_dead_time.c +cf_electronics_dead_time.o: cf_electronics_dead_time.c +cf_fifo_dead_time.o: cf_fifo_dead_time.c +cf_apply_dead_time.o: cf_apply_dead_time.c +cf_thermal_distort.o: cf_thermal_distort.c +cf_count_rate_y_distort.o: cf_count_rate_y_distort.c +cf_time_xy_distort.o : cf_time_xy_distort.c +cf_geometric_distort: cf_geometric_distort.c +cf_pha_x_distort.o: cf_pha_x_distort.c +cf_active_region.o: cf_active_region.c +cf_find_spectra.o: cf_find_spectra.c +cf_identify_channel.o: cf_identify_channel.c +cf_init_support.o: cf_init_support.c +cf_target_count_rate.o: cf_target_count_rate.c +cf_calculate_ycent_motion.o: cf_calculate_ycent_motion.c +cf_source_aper.o: cf_source_aper.c +cf_grating_motion.o: cf_grating_motion.c +cf_fpa_position.o: cf_fpa_position.c +cf_read_fpa_pos.o: cf_read_fpa_pos.c +cf_make_mask.o: cf_make_mask.c +cf_mirror_motion.o: cf_mirror_motion.c +cf_satellite_jitter.o: cf_satellite_jitter.c +cf_calculate_y_centroid.o: cf_calculate_y_centroid.c +cf_screen_airglow.o: cf_screen_airglow.c +cf_screen_bad_pixels.o: cf_screen_bad_pixels.c +cf_screen_jitter.o: cf_screen_jitter.c +cf_screen_limb_angle.o: cf_screen_limb_angle.c +cf_screen_saa.o: cf_screen_saa.c +cf_screen_high_voltage.o: cf_screen_high_voltage.c +cf_screen_burst.o: cf_screen_burst.c +cf_set_user_gtis.o: cf_set_user_gtis.c +cf_set_photon_flags.o: cf_set_photon_flags.c +cf_set_good_time_intervals.o: cf_set_good_time_intervals.c +cf_modify_hist_pha.o: cf_modify_hist_pha.c +cf_modify_hist_times.o: cf_modify_hist_times.c +cf_screen_pulse_height.o: cf_screen_pulse_height.c +cf_convert_to_ergs.o: cf_convert_to_ergs.c +cf_extraction_limits.o: cf_extraction_limits.c +cf_astigmatism.o: cf_astigmatism.c +cf_dispersion.o: cf_dispersion.c +cf_doppler_and_heliocentric.o: cf_doppler_and_heliocentric.c +cf_apply_filters.o: cf_apply_filters.c +cf_scale_bkgd.o: cf_scale_bkgd.c +cf_make_mask.o: cf_make_mask.c +cf_make_wave_array.o: cf_make_wave_array.c +cf_rebin_background.o: cf_rebin_background.c +cf_rebin_probability_array.o: cf_rebin_probability_array.c +cf_standard_or_optimal_extraction.o: cf_standard_or_optimal_extraction.c +cf_optimal_extraction.o: cf_optimal_extraction.c +cf_write_extracted_spectrum.o: cf_write_extracted_spectrum.c + diff --git a/src/libcf/Makefile.MacOSX.orig b/src/libcf/Makefile.MacOSX.orig new file mode 100644 index 0000000..eade1ea --- /dev/null +++ b/src/libcf/Makefile.MacOSX.orig @@ -0,0 +1,152 @@ +LIBRARY= libcf + +CALFUSEDIR= ${PWD}/../.. +SHARED= -dynamiclib +FITSVER= 2.470 + +# Symbols for include directories +FUSEINCLDIR= -I${CALFUSEDIR}/include + +# Symbols used for compiling +CC= cc +OPT= -O3 -Wall -DCFORTRAN -Dg77Fortran -Df2cFortran +CFLAGS= ${OPT} ${FUSEINCLDIR} + +FUSELIBDIR= -L${CALFUSEDIR}/lib +# FUSELIBS= -lcfitsio-${FITSVER} -lsla +FUSELIBS= -lcfitsio -lsla +LIBS= -lc -lm -ldl -L/sw/lib/ -lgfortran + +# Symbols used for creating shared libraries + +SO= .dylib + +OBJS= calfits.o sgp4.o eclipse.o saa.o \ + state_limb.o state_geod.o space_vel.o helio_vel.o \ + geod_mag.o pole_ang.o solar_ang.o lsrd_vel.o lsrk_vel.o \ + month_day.o read_tle.o cf_velang.o \ + set_orbit_parms.o cf_error_msg.o \ + cf_cal_file.o cf_proc_check.o cf_proc_update.o \ + cf_timestamp.o cf_fuv_init.o cf_header_io.o \ + cf_check_digitizer.o cf_nint.o \ + cf_idf_io.o cf_ids_dead_time.o cf_electronics_dead_time.o \ + cf_fifo_dead_time.o cf_apply_dead_time.o \ + cf_thermal_distort.o cf_count_rate_y_distort.o cf_time_xy_distort.o \ + cf_geometric_distort.o cf_pha_x_distort.o \ + cf_active_region.o cf_find_spectra.o cf_identify_channel.o \ + cf_calculate_ycent_motion.o cf_source_aper.o\ + cf_grating_motion.o cf_fpa_position.o cf_read_fpa_pos.o \ + cf_make_mask.o cf_mirror_motion.o \ + cf_satellite_jitter.o cf_calculate_y_centroid.o \ + cf_target_count_rate.o \ + cf_screen_jitter.o cf_screen_limb_angle.o cf_screen_saa.o \ + cf_screen_high_voltage.o cf_screen_burst.o cf_screen_airglow.o \ + cf_screen_bad_pixels.o cf_set_user_gtis.o \ + cf_set_photon_flags.o cf_set_good_time_intervals.o \ + cf_modify_hist_times.o cf_screen_pulse_height.o \ + cf_convert_to_ergs.o cf_extraction_limits.o \ + cf_astigmatism.o cf_dispersion.o cf_doppler_and_heliocentric.o \ + cf_apply_filters.o cf_scale_bkgd.o \ + cf_make_wave_array.o cf_rebin_background.o \ + cf_rebin_probability_array.o cf_optimal_extraction.o \ + cf_write_extracted_spectrum.o cf_standard_or_optimal_extraction.o \ + cf_init_support.o cf_modify_hist_pha.o \ + cf_fes_proc_check.o cf_fes_proc_update.o + +all: ${OBJS} + ${CC} ${SHARED} -o ${LIBRARY}${SO} ${OBJS} \ + ${FUSELIBDIR} ${FUSELIBS} ${LIBS} + +install: all + chmod g+w ${OBJS} ${LIBRARY}${SO} + /bin/cp -p ${LIBRARY}${SO} ${CALFUSEDIR}/lib/${LIBRARY}${SO} + +clean: + - /bin/rm -f *.o ${LIBRARY}${SO} ${LIBRARY}${O} + +distclean: + - /bin/rm -f *.o ${LIBRARY}${SO} ${LIBRARY}${O} + cd ../../lib; /bin/rm -f ${LIBRARY}${SO} + +calfits.o: calfits.c +sgp4.o: sgp4.c +eclipse.o: eclipse.c +set_orbit_parms.o: set_orbit_parms.c +saa.o: saa.c +state_limb.o: state_limb.c +state_geod.o: state_geod.c +space_vel.o: space_vel.c +helio_vel.o: helio_vel.c +geod_mag.o: geod_mag.c +pole_ang.o: pole_ang.c +solar_ang.o: solar_ang.c +lsrd_vel.o: lsrd_vel.c +lsrk_vel.o: lsrk_vel.c +month_day.o: month_day.c +read_tle.o: read_tle.c + +cf_error_msg.o: cf_error_msg.c +cf_cal_file.o: cf_cal_file.c +cf_fes_proc_check.o: cf_fes_proc_check.c +cf_fes_proc_update.o: cf_fes_proc_update.c +cf_proc_check.o: cf_proc_check.c +cf_proc_update.o: cf_proc_update.c +cf_fuv_init.o: cf_fuv_init.c +cf_velang.o: cf_velang.c +cf_timestamp.o: cf_timestamp.c + +cf_header_io.o: cf_header_io.c +cf_check_digitizer.o: cf_check_digitizer.c +cf_nint.o: cf_nint.c +cf_idf_io.o: cf_idf_io.c +cf_ids_dead_time.o: cf_ids_dead_time.c +cf_electronics_dead_time.o: cf_electronics_dead_time.c +cf_apply_dead_time.o: cf_apply_dead_time.c +cf_fifo_dead_time.o: cf_fifo_dead_time.c +cf_thermal_distort.o: cf_thermal_distort.c +cf_count_rate_y_distort.o: cf_count_rate_y_distort.c +cf_time_xy_distort.o : cf_time_xy_distort.c +cf_geometric_distort: cf_geometric_distort.c +cf_pha_x_distort.o: cf_pha_x_distort.c +cf_active_region.o: cf_active_region.c +cf_find_spectra.o: cf_find_spectra.c +cf_identify_channel.o: cf_identify_channel.c +cf_init_support.o: cf_init_support.c +cf_target_count_rate.o: cf_target_count_rate.c +cf_calculate_ycent_motion.o: cf_calculate_ycent_motion.c +cf_source_aper.o: cf_source_aper.c +cf_grating_motion.o: cf_grating_motion.c +cf_fpa_position.o: cf_fpa_position.c +cf_read_fpa_pos.o: cf_read_fpa_pos.c +cf_make_mask.o: cf_make_mask.c +cf_mirror_motion.o: cf_mirror_motion.c +cf_satellite_jitter.o: cf_satellite_jitter.c +cf_calculate_y_centroid.o: cf_calculate_y_centroid.c +cf_screen_airglow.o: cf_screen_airglow.c +cf_screen_bad_pixels.o: cf_screen_bad_pixels.c +cf_screen_jitter.o: cf_screen_jitter.c +cf_screen_limb_angle.o: cf_screen_limb_angle.c +cf_screen_saa.o: cf_screen_saa.c +cf_screen_high_voltage.o: cf_screen_high_voltage.c +cf_screen_burst.o: cf_screen_burst.c +cf_set_user_gtis.o: cf_set_user_gtis.c +cf_set_photon_flags.o: cf_set_photon_flags.c +cf_set_good_time_intervals.o: cf_set_good_time_intervals.c +cf_modify_hist_pha.o: cf_modify_hist_pha.c +cf_modify_hist_times.o: cf_modify_hist_times.c +cf_screen_pulse_height.o: cf_screen_pulse_height.c +cf_convert_to_ergs.o: cf_convert_to_ergs.c +cf_extraction_limits.o: cf_extraction_limits.c +cf_astigmatism.o: cf_astigmatism.c +cf_dispersion.o: cf_dispersion.c +cf_doppler_and_heliocentric.o: cf_doppler_and_heliocentric.c +cf_apply_filters.o: cf_apply_filters.c +cf_scale_bkgd.o: cf_scale_bkgd.c +cf_make_mask.o: cf_make_mask.c +cf_make_wave_array.o: cf_make_wave_array.c +cf_rebin_background.o: cf_rebin_background.c +cf_rebin_probability_array.o: cf_rebin_probability_array.c +cf_standard_or_optimal_extraction.o: cf_standard_or_optimal_extraction.c +cf_optimal_extraction.o: cf_optimal_extraction.c +cf_write_extracted_spectrum.o: cf_write_extracted_spectrum.c + diff --git a/src/libcf/Makefile.Solaris.orig b/src/libcf/Makefile.Solaris.orig new file mode 100644 index 0000000..f817dfe --- /dev/null +++ b/src/libcf/Makefile.Solaris.orig @@ -0,0 +1,152 @@ +LIBRARY= libcf + +CALFUSEDIR= ${PWD}/../.. +SHARED= -G +FITSVER= 2.470 + +# Symbols for include directories +FUSEINCLDIR= -I${CALFUSEDIR}/include + +# Symbols used for compiling +CC= cc +# OPT= -p -v -xO2 -xdepend -xchip=ultra -xarch=generic +OPT= -O -DCFORTRAN -KPIC +CFLAGS= ${OPT} ${FUSEINCLDIR} + +FUSELIBDIR= -L${CALFUSEDIR}/lib +FUSELIBS= -lcfitsio-${FITSVER} -lsla +LIBS= -lc -lm -lnsl -ldl -lsocket +LDFLAGS= + +# Symbols used for creating shared libraries + +SO= .so + +OBJS= calfits.o sgp4.o eclipse.o saa.o \ + state_limb.o state_geod.o space_vel.o helio_vel.o \ + geod_mag.o pole_ang.o solar_ang.o lsrd_vel.o lsrk_vel.o \ + month_day.o read_tle.o cf_velang.o \ + set_orbit_parms.o cf_error_msg.o \ + cf_cal_file.o cf_proc_check.o cf_proc_update.o \ + cf_timestamp.o cf_fuv_init.o cf_header_io.o \ + cf_check_digitizer.o cf_nint.o \ + cf_idf_io.o cf_ids_dead_time.o cf_electronics_dead_time.o \ + cf_fifo_dead_time.o cf_apply_dead_time.o \ + cf_thermal_distort.o cf_count_rate_y_distort.o cf_time_xy_distort.o \ + cf_geometric_distort.o cf_pha_x_distort.o \ + cf_active_region.o cf_find_spectra.o cf_identify_channel.o \ + cf_calculate_ycent_motion.o cf_source_aper.o\ + cf_grating_motion.o cf_fpa_position.o cf_read_fpa_pos.o \ + cf_make_mask.o cf_mirror_motion.o \ + cf_satellite_jitter.o cf_calculate_y_centroid.o \ + cf_target_count_rate.o \ + cf_screen_jitter.o cf_screen_limb_angle.o cf_screen_saa.o \ + cf_screen_high_voltage.o cf_screen_burst.o cf_screen_airglow.o \ + cf_screen_bad_pixels.o cf_set_user_gtis.o \ + cf_set_photon_flags.o cf_set_good_time_intervals.o \ + cf_modify_hist_times.o cf_screen_pulse_height.o \ + cf_convert_to_ergs.o cf_extraction_limits.o \ + cf_astigmatism.o cf_dispersion.o cf_doppler_and_heliocentric.o \ + cf_apply_filters.o cf_scale_bkgd.o \ + cf_make_wave_array.o cf_rebin_background.o \ + cf_rebin_probability_array.o cf_optimal_extraction.o \ + cf_write_extracted_spectrum.o cf_standard_or_optimal_extraction.o \ + cf_init_support.o cf_modify_hist_pha.o \ + cf_fes_proc_check.o cf_fes_proc_update.o + +all: ${OBJS} + ${CC} ${SHARED} -o ${LIBRARY}${SO} ${OBJS} \ + ${FUSELIBDIR} ${FUSELIBS} ${LIBS} ${LDFLAGS} + +install: all + chmod g+w ${OBJS} ${LIBRARY}${SO} + /bin/cp -p ${LIBRARY}${SO} ${CALFUSEDIR}/lib/${LIBRARY}${SO} + +clean: + - /bin/rm -f *.o ${LIBRARY}${SO} ${LIBRARY}${O} + +distclean: + - /bin/rm -f *.o ${LIBRARY}${SO} ${LIBRARY}${O} + cd ../../lib; /bin/rm -f ${LIBRARY}${SO} + +calfits.o: calfits.c +sgp4.o: sgp4.c +eclipse.o: eclipse.c +set_orbit_parms.o: set_orbit_parms.c +saa.o: saa.c +state_limb.o: state_limb.c +state_geod.o: state_geod.c +space_vel.o: space_vel.c +helio_vel.o: helio_vel.c +geod_mag.o: geod_mag.c +pole_ang.o: pole_ang.c +solar_ang.o: solar_ang.c +lsrd_vel.o: lsrd_vel.c +lsrk_vel.o: lsrk_vel.c +month_day.o: month_day.c +read_tle.o: read_tle.c + +cf_error_msg.o: cf_error_msg.c +cf_cal_file.o: cf_cal_file.c +cf_fes_proc_check.o: cf_fes_proc_check.c +cf_fes_proc_update.o: cf_fes_proc_update.c +cf_proc_check.o: cf_proc_check.c +cf_proc_update.o: cf_proc_update.c +cf_fuv_init.o: cf_fuv_init.c +cf_velang.o: cf_velang.c +cf_timestamp.o: cf_timestamp.c + +cf_header_io.o: cf_header_io.c +cf_check_digitizer.o: cf_check_digitizer.c +cf_nint.o: cf_nint.c +cf_idf_io.o: cf_idf_io.c +cf_ids_dead_time.o: cf_ids_dead_time.c +cf_electronics_dead_time.o: cf_electronics_dead_time.c +cf_apply_dead_time.o: cf_apply_dead_time.c +cf_fifo_dead_time.o: cf_fifo_dead_time.c +cf_thermal_distort.o: cf_thermal_distort.c +cf_count_rate_y_distort.o: cf_count_rate_y_distort.c +cf_time_xy_distort.o : cf_time_xy_distort.c +cf_geometric_distort: cf_geometric_distort.c +cf_pha_x_distort.o: cf_pha_x_distort.c +cf_active_region.o: cf_active_region.c +cf_find_spectra.o: cf_find_spectra.c +cf_identify_channel.o: cf_identify_channel.c +cf_init_support.o: cf_init_support.c +cf_target_count_rate.o: cf_target_count_rate.c +cf_calculate_ycent_motion.o: cf_calculate_ycent_motion.c +cf_source_aper.o: cf_source_aper.c +cf_grating_motion.o: cf_grating_motion.c +cf_fpa_position.o: cf_fpa_position.c +cf_read_fpa_pos.o: cf_read_fpa_pos.c +cf_make_mask.o: cf_make_mask.c +cf_mirror_motion.o: cf_mirror_motion.c +cf_satellite_jitter.o: cf_satellite_jitter.c +cf_calculate_y_centroid.o: cf_calculate_y_centroid.c +cf_screen_airglow.o: cf_screen_airglow.c +cf_screen_bad_pixels.o: cf_screen_bad_pixels.c +cf_screen_jitter.o: cf_screen_jitter.c +cf_screen_limb_angle.o: cf_screen_limb_angle.c +cf_screen_saa.o: cf_screen_saa.c +cf_screen_high_voltage.o: cf_screen_high_voltage.c +cf_screen_burst.o: cf_screen_burst.c +cf_set_user_gtis.o: cf_set_user_gtis.c +cf_set_photon_flags.o: cf_set_photon_flags.c +cf_set_good_time_intervals.o: cf_set_good_time_intervals.c +cf_modify_hist_pha.o: cf_modify_hist_pha.c +cf_modify_hist_times.o: cf_modify_hist_times.c +cf_screen_pulse_height.o: cf_screen_pulse_height.c +cf_convert_to_ergs.o: cf_convert_to_ergs.c +cf_extraction_limits.o: cf_extraction_limits.c +cf_astigmatism.o: cf_astigmatism.c +cf_dispersion.o: cf_dispersion.c +cf_doppler_and_heliocentric.o: cf_doppler_and_heliocentric.c +cf_apply_filters.o: cf_apply_filters.c +cf_scale_bkgd.o: cf_scale_bkgd.c +cf_make_mask.o: cf_make_mask.c +cf_make_wave_array.o: cf_make_wave_array.c +cf_rebin_background.o: cf_rebin_background.c +cf_rebin_probability_array.o: cf_rebin_probability_array.c +cf_standard_or_optimal_extraction.o: cf_standard_or_optimal_extraction.c +cf_optimal_extraction.o: cf_optimal_extraction.c +cf_write_extracted_spectrum.o: cf_write_extracted_spectrum.c diff --git a/src/libcf/Makefile.orig.orig b/src/libcf/Makefile.orig.orig new file mode 100644 index 0000000..f817dfe --- /dev/null +++ b/src/libcf/Makefile.orig.orig @@ -0,0 +1,152 @@ +LIBRARY= libcf + +CALFUSEDIR= ${PWD}/../.. +SHARED= -G +FITSVER= 2.470 + +# Symbols for include directories +FUSEINCLDIR= -I${CALFUSEDIR}/include + +# Symbols used for compiling +CC= cc +# OPT= -p -v -xO2 -xdepend -xchip=ultra -xarch=generic +OPT= -O -DCFORTRAN -KPIC +CFLAGS= ${OPT} ${FUSEINCLDIR} + +FUSELIBDIR= -L${CALFUSEDIR}/lib +FUSELIBS= -lcfitsio-${FITSVER} -lsla +LIBS= -lc -lm -lnsl -ldl -lsocket +LDFLAGS= + +# Symbols used for creating shared libraries + +SO= .so + +OBJS= calfits.o sgp4.o eclipse.o saa.o \ + state_limb.o state_geod.o space_vel.o helio_vel.o \ + geod_mag.o pole_ang.o solar_ang.o lsrd_vel.o lsrk_vel.o \ + month_day.o read_tle.o cf_velang.o \ + set_orbit_parms.o cf_error_msg.o \ + cf_cal_file.o cf_proc_check.o cf_proc_update.o \ + cf_timestamp.o cf_fuv_init.o cf_header_io.o \ + cf_check_digitizer.o cf_nint.o \ + cf_idf_io.o cf_ids_dead_time.o cf_electronics_dead_time.o \ + cf_fifo_dead_time.o cf_apply_dead_time.o \ + cf_thermal_distort.o cf_count_rate_y_distort.o cf_time_xy_distort.o \ + cf_geometric_distort.o cf_pha_x_distort.o \ + cf_active_region.o cf_find_spectra.o cf_identify_channel.o \ + cf_calculate_ycent_motion.o cf_source_aper.o\ + cf_grating_motion.o cf_fpa_position.o cf_read_fpa_pos.o \ + cf_make_mask.o cf_mirror_motion.o \ + cf_satellite_jitter.o cf_calculate_y_centroid.o \ + cf_target_count_rate.o \ + cf_screen_jitter.o cf_screen_limb_angle.o cf_screen_saa.o \ + cf_screen_high_voltage.o cf_screen_burst.o cf_screen_airglow.o \ + cf_screen_bad_pixels.o cf_set_user_gtis.o \ + cf_set_photon_flags.o cf_set_good_time_intervals.o \ + cf_modify_hist_times.o cf_screen_pulse_height.o \ + cf_convert_to_ergs.o cf_extraction_limits.o \ + cf_astigmatism.o cf_dispersion.o cf_doppler_and_heliocentric.o \ + cf_apply_filters.o cf_scale_bkgd.o \ + cf_make_wave_array.o cf_rebin_background.o \ + cf_rebin_probability_array.o cf_optimal_extraction.o \ + cf_write_extracted_spectrum.o cf_standard_or_optimal_extraction.o \ + cf_init_support.o cf_modify_hist_pha.o \ + cf_fes_proc_check.o cf_fes_proc_update.o + +all: ${OBJS} + ${CC} ${SHARED} -o ${LIBRARY}${SO} ${OBJS} \ + ${FUSELIBDIR} ${FUSELIBS} ${LIBS} ${LDFLAGS} + +install: all + chmod g+w ${OBJS} ${LIBRARY}${SO} + /bin/cp -p ${LIBRARY}${SO} ${CALFUSEDIR}/lib/${LIBRARY}${SO} + +clean: + - /bin/rm -f *.o ${LIBRARY}${SO} ${LIBRARY}${O} + +distclean: + - /bin/rm -f *.o ${LIBRARY}${SO} ${LIBRARY}${O} + cd ../../lib; /bin/rm -f ${LIBRARY}${SO} + +calfits.o: calfits.c +sgp4.o: sgp4.c +eclipse.o: eclipse.c +set_orbit_parms.o: set_orbit_parms.c +saa.o: saa.c +state_limb.o: state_limb.c +state_geod.o: state_geod.c +space_vel.o: space_vel.c +helio_vel.o: helio_vel.c +geod_mag.o: geod_mag.c +pole_ang.o: pole_ang.c +solar_ang.o: solar_ang.c +lsrd_vel.o: lsrd_vel.c +lsrk_vel.o: lsrk_vel.c +month_day.o: month_day.c +read_tle.o: read_tle.c + +cf_error_msg.o: cf_error_msg.c +cf_cal_file.o: cf_cal_file.c +cf_fes_proc_check.o: cf_fes_proc_check.c +cf_fes_proc_update.o: cf_fes_proc_update.c +cf_proc_check.o: cf_proc_check.c +cf_proc_update.o: cf_proc_update.c +cf_fuv_init.o: cf_fuv_init.c +cf_velang.o: cf_velang.c +cf_timestamp.o: cf_timestamp.c + +cf_header_io.o: cf_header_io.c +cf_check_digitizer.o: cf_check_digitizer.c +cf_nint.o: cf_nint.c +cf_idf_io.o: cf_idf_io.c +cf_ids_dead_time.o: cf_ids_dead_time.c +cf_electronics_dead_time.o: cf_electronics_dead_time.c +cf_apply_dead_time.o: cf_apply_dead_time.c +cf_fifo_dead_time.o: cf_fifo_dead_time.c +cf_thermal_distort.o: cf_thermal_distort.c +cf_count_rate_y_distort.o: cf_count_rate_y_distort.c +cf_time_xy_distort.o : cf_time_xy_distort.c +cf_geometric_distort: cf_geometric_distort.c +cf_pha_x_distort.o: cf_pha_x_distort.c +cf_active_region.o: cf_active_region.c +cf_find_spectra.o: cf_find_spectra.c +cf_identify_channel.o: cf_identify_channel.c +cf_init_support.o: cf_init_support.c +cf_target_count_rate.o: cf_target_count_rate.c +cf_calculate_ycent_motion.o: cf_calculate_ycent_motion.c +cf_source_aper.o: cf_source_aper.c +cf_grating_motion.o: cf_grating_motion.c +cf_fpa_position.o: cf_fpa_position.c +cf_read_fpa_pos.o: cf_read_fpa_pos.c +cf_make_mask.o: cf_make_mask.c +cf_mirror_motion.o: cf_mirror_motion.c +cf_satellite_jitter.o: cf_satellite_jitter.c +cf_calculate_y_centroid.o: cf_calculate_y_centroid.c +cf_screen_airglow.o: cf_screen_airglow.c +cf_screen_bad_pixels.o: cf_screen_bad_pixels.c +cf_screen_jitter.o: cf_screen_jitter.c +cf_screen_limb_angle.o: cf_screen_limb_angle.c +cf_screen_saa.o: cf_screen_saa.c +cf_screen_high_voltage.o: cf_screen_high_voltage.c +cf_screen_burst.o: cf_screen_burst.c +cf_set_user_gtis.o: cf_set_user_gtis.c +cf_set_photon_flags.o: cf_set_photon_flags.c +cf_set_good_time_intervals.o: cf_set_good_time_intervals.c +cf_modify_hist_pha.o: cf_modify_hist_pha.c +cf_modify_hist_times.o: cf_modify_hist_times.c +cf_screen_pulse_height.o: cf_screen_pulse_height.c +cf_convert_to_ergs.o: cf_convert_to_ergs.c +cf_extraction_limits.o: cf_extraction_limits.c +cf_astigmatism.o: cf_astigmatism.c +cf_dispersion.o: cf_dispersion.c +cf_doppler_and_heliocentric.o: cf_doppler_and_heliocentric.c +cf_apply_filters.o: cf_apply_filters.c +cf_scale_bkgd.o: cf_scale_bkgd.c +cf_make_mask.o: cf_make_mask.c +cf_make_wave_array.o: cf_make_wave_array.c +cf_rebin_background.o: cf_rebin_background.c +cf_rebin_probability_array.o: cf_rebin_probability_array.c +cf_standard_or_optimal_extraction.o: cf_standard_or_optimal_extraction.c +cf_optimal_extraction.o: cf_optimal_extraction.c +cf_write_extracted_spectrum.o: cf_write_extracted_spectrum.c diff --git a/src/libcf/calfits.c b/src/libcf/calfits.c new file mode 100644 index 0000000..29b3a08 --- /dev/null +++ b/src/libcf/calfits.c @@ -0,0 +1,658 @@ +/***************************************************************************** + * Johns Hopkins University + * Center For Astrophysical Sciences + * FUSE + ***************************************************************************** + * + * Description: Wrappers for cfitsio routines which includes error checking. + * + * History: 04/14/99 peb Finished work on subset of routines + * from cfitsio v2.031. + * 04/15/99 emm Replaced #include FITSIO.h with + * #include calfuse.h + * 04/15/99 barrett Added FITS_get_rowsize. + * 04/16/99 barrett Added FITS_get_hdu_num. + * 04/20/99 barrett Added FITS_insert_key_[str, log, lng, + * fixflt, flt, fixdbl, dbl, fixcmp, + * cmp, fixdblcmp, dblcmp] + * 04/23/99 emurphy Deleted error checking from + * cf_get_hdu_num + * 04/04/01 kruk Force casesen to FALSE in FITS_get_colnum + * 12/18/03 bjg Change calfusettag.h to calfuse.h + * + ****************************************************************************/ + +#include "fitsio.h" +#include "calfuse.h" + +int FITS_open_file(fitsfile **fptr, const char *filename, int iomode, + int *status) +{ + ffopen(fptr, filename, iomode, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_reopen_file(fitsfile *openfptr, fitsfile **newfptr, int *status) +{ + ffreopen(openfptr, newfptr, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_create_file(fitsfile **fptr, const char *filename, int *status) +{ + ffinit(fptr, filename, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_flush_file(fitsfile *fptr, int *status) +{ + ffflus(fptr, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_close_file(fitsfile *fptr, int *status) +{ + ffclos(fptr, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_delete_file(fitsfile *fptr, int *status) +{ + ffdelt(fptr, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_file_name(fitsfile *fptr, char *filename, int *status) +{ + ffflnm(fptr, filename, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_file_mode(fitsfile *fptr, int *filemode, int *status) +{ + ffflmd(fptr, filemode, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_write_record(fitsfile *fptr, const char *card, int *status) +{ + ffprec(fptr, card, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_write_key(fitsfile *fptr, int datatype, char *keyname, void *value, + char *comm, int *status) +{ + ffpky(fptr, datatype, keyname, value, + comm, status); + if (*status) fprintf(stderr, "Error writing keyword %16.16s\n",keyname); + cf_if_fits_error(*status); + return *status; +} + +int FITS_write_comment(fitsfile *fptr, const char *comm, int *status) +{ + ffpcom(fptr, comm, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_write_history(fitsfile *fptr, const char *history, int *status) +{ + ffphis(fptr, history, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_write_date(fitsfile *fptr, int *status) +{ + ffpdat(fptr, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_copy_key(fitsfile *infptr,fitsfile *outfptr,int incol,int outcol, + char *rootname, int *status) +{ + ffcpky(infptr,outfptr,incol,outcol, + rootname, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_write_imghdr(fitsfile *fptr, int bitpix, int naxis, long naxes[], + int *status) +{ + ffphps( fptr, bitpix, naxis, naxes, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_write_grphdr(fitsfile *fptr, int simple, int bitpix, int naxis, + long naxes[], long pcount, long gcount, int extend, + int *status) +{ + ffphpr( fptr, simple, bitpix, naxis, naxes, + pcount, gcount, extend, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_write_btblhdr(fitsfile *fptr, long naxis2, int tfields, char **ttype, + char **tform, char **tunit, char *extname, long pcount, + int *status) +{ + ffphbn(fptr, naxis2, tfields, ttype, + tform, tunit, extname, pcount, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_get_hdrpos(fitsfile *fptr, int *nexist, int *position, int *status) +{ + ffghps(fptr, nexist, position, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_read_record(fitsfile *fptr, int nrec, char *card, int *status) +{ + ffgrec(fptr, nrec, card, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_read_card(fitsfile *fptr, char *keyname, char *card, int *status) +{ + ffgcrd(fptr, keyname, card, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_read_key(fitsfile *fptr, int datatype, char *keyname, void *value, + char *comm, int *status) +{ + ffgky( fptr, datatype, keyname, value, + comm, status); + if (*status) fprintf(stderr, "Error reading keyword %16.16s\n",keyname); + cf_if_fits_error(*status); + return *status; +} + +int FITS_read_imghdr(fitsfile *fptr, int maxdim, int *simple, int *bitpix, + int *naxis, long naxes[], long *pcount, long *gcount, + int *extend, int *status) +{ + ffghpr(fptr, maxdim, simple, bitpix, naxis, + naxes, pcount, gcount, extend, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_read_btblhdr(fitsfile *fptr, int maxfield, long *naxis2, int *tfields, + char **ttype, char **tform, char **tunit, char *extname, + long *pcount, int *status) +{ + ffghbn(fptr, maxfield, naxis2, tfields, + ttype, tform, tunit, extname, + pcount, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_update_card(fitsfile *fptr, char *keyname, char *card, int *status) +{ + ffucrd(fptr, keyname, card, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_update_key(fitsfile *fptr, int datatype, char *keyname, void *value, + char *comm, int *status) +{ + ffuky(fptr, datatype, keyname, value, + comm, status); + if (*status) fprintf(stderr, "Error updating keyword %16.16s\n",keyname); + cf_if_fits_error(*status); + return *status; +} + +int FITS_modify_record(fitsfile *fptr, int nkey, char *card, int *status) +{ + ffmrec(fptr, nkey, card, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_modify_card(fitsfile *fptr, char *keyname, char *card, int *status) +{ + ffmcrd(fptr, keyname, card, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_modify_comment(fitsfile *fptr, char *keyname, char *comm, int *status) +{ + ffmcom(fptr, keyname, comm, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_insert_record(fitsfile *fptr, int nkey, char *card, int *status) +{ + ffirec(fptr, nkey, card, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_insert_key_str(fitsfile *fptr, char *keyname, char *value, + char *comment, int *status) +{ + ffikys(fptr, keyname, value, comment, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_insert_key_log(fitsfile *fptr, char *keyname, int value, + char *comment, int *status) +{ + ffikyl(fptr, keyname, value, comment, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_insert_key_lng(fitsfile *fptr, char *keyname, long value, + char *comment, int *status) +{ + ffikyj(fptr, keyname, value, comment, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_insert_key_flt(fitsfile *fptr, char *keyname, float value, + int decimals, char *comment, int *status) +{ + ffikye(fptr, keyname, value, decimals, comment, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_insert_key_fixflt(fitsfile *fptr, char *keyname, float value, + int decimals, char *comment, int *status) +{ + ffikyf(fptr, keyname, value, decimals, comment, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_insert_key_dbl(fitsfile *fptr, char *keyname, double value, + int decimals, char *comment, int *status) +{ + ffikyd(fptr, keyname, value, decimals, comment, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_insert_key_fixdbl(fitsfile *fptr, char *keyname, double value, + int decimals, char *comment, int *status) +{ + ffikyg(fptr, keyname, value, decimals, comment, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_insert_key_cmp(fitsfile *fptr, char *keyname, float *value, + int decimals, char *comment, int *status) +{ + ffikyc(fptr, keyname, value, decimals, comment, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_insert_key_dblcmp(fitsfile *fptr, char *keyname, double *value, + int decimals, char *comment, int *status) +{ + ffikym(fptr, keyname, value, decimals, comment, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_insert_key_fixcmp(fitsfile *fptr, char *keyname, float *value, + int decimals, char *comment, int *status) +{ + ffikfc(fptr, keyname, value, decimals, comment, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_insert_key_fixdblcmp(fitsfile *fptr, char *keyname, double *value, + int decimals, char *comment, int *status) +{ + ffikfm(fptr, keyname, value, decimals, comment, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_insert_key_null(fitsfile *fptr, char *keyname, char *comment, + int *status) +{ + ffikyu(fptr, keyname, comment, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_delete_key(fitsfile *fptr, char *keyname, int *status) +{ + ffdkey(fptr, keyname, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_delete_record(fitsfile *fptr, int keypos, int *status) +{ + ffdrec(fptr, keypos, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_get_hdu_num(fitsfile *fptr, int *hdunum) +{ + /* This routine returns the HDU number instead of status. Therefore, + * it should not use any error checking. */ + int status; + status = ffghdn(fptr, hdunum); + return status; +} + +int FITS_get_hdu_type(fitsfile *fptr, int *exttype, int *status) +{ + ffghdt(fptr, exttype, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_movabs_hdu(fitsfile *fptr, int hdunum, int *exttype, int *status) +{ + ffmahd(fptr, hdunum, exttype, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_movrel_hdu(fitsfile *fptr, int hdumov, int *exttype, int *status) +{ + ffmrhd(fptr, hdumov, exttype, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_movnam_hdu(fitsfile *fptr, int exttype, char *hduname, int hduvers, + int *status) +{ + ffmnhd(fptr, exttype, hduname, hduvers, + status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_get_num_hdus(fitsfile *fptr, int *nhdu, int *status) +{ + ffthdu(fptr, nhdu, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_create_img(fitsfile *fptr, int bitpix, int naxis, long *naxes, + int *status) +{ + ffcrim(fptr, bitpix, naxis, naxes, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_create_tbl(fitsfile *fptr, int tbltype, long naxis2, int tfields, + char **ttype, char **tform, char **tunit, char *extname, + int *status) +{ + ffcrtb(fptr, tbltype, naxis2, tfields, ttype, + tform, tunit, extname, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_create_hdu(fitsfile *fptr, int *status) +{ + ffcrhd(fptr, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_insert_img(fitsfile *fptr, int bitpix, int naxis, long *naxes, + int *status) +{ + ffiimg(fptr, bitpix, naxis, naxes, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_insert_atbl(fitsfile *fptr, long naxis1, long naxis2, int tfields, + char **ttype, long *tbcol, char **tform, char **tunit, + char *extname, int *status) +{ + ffitab(fptr, naxis1, naxis2, tfields, ttype, + tbcol, tform, tunit, extname, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_insert_btbl(fitsfile *fptr,long naxis2, int tfields, char **ttype, + char **tform, char **tunit, char *extname, long pcount, + int *status) +{ + ffibin(fptr,naxis2, tfields, ttype, tform, + tunit, extname, pcount, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_delete_hdu(fitsfile *fptr, int *hdutype, int *status) +{ + ffdhdu(fptr, hdutype, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_copy_hdu(fitsfile *infptr, fitsfile *outfptr, int morekeys, + int *status) +{ + ffcopy(infptr, outfptr, morekeys, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_copy_header(fitsfile *infptr, fitsfile *outfptr, int *status) +{ + ffcphd(infptr, outfptr, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_copy_data(fitsfile *infptr, fitsfile *outfptr, int *status) +{ + ffcpdt(infptr, outfptr, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_get_colnum(fitsfile *fptr, int casesen, char *templt, int *colnum, + int *status) +{ + /* force casesen to FALSE, in accordance with the FITS standard */ + casesen = FALSE; + ffgcno(fptr, casesen, templt, colnum, + status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_get_colname(fitsfile *fptr, int casesen, char *templt, char *colname, + int *colnum, int *status) +{ + ffgcnn(fptr, casesen, templt, colname, + colnum, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_get_coltype(fitsfile *fptr, int colnum, int *typecode, long *repeat, + long *width, int *status) +{ + ffgtcl(fptr, colnum, typecode, repeat, + width, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_get_num_rows(fitsfile *fptr, long *nrows, int *status) +{ + ffgnrw(fptr, nrows, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_get_rowsize(fitsfile *fptr, long *nrows, int *status) +{ + ffgrsz(fptr, nrows, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_get_num_cols(fitsfile *fptr, int *ncols, int *status) +{ + ffgncl(fptr, ncols, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_get_acolparms(fitsfile *fptr, int colnum, char *ttype, long *tbcol, + char *tunit, char *tform, double *tscal, double *tzero, + char *tnull, char *tdisp, int *status) +{ + ffgacl(fptr, colnum, ttype, tbcol, + tunit, tform, tscal, tzero, + tnull, tdisp, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_get_bcolparms(fitsfile *fptr, int colnum, char *ttype, char *tunit, + char *dtype, long *repeat, double *tscal, double *tzero, + long *tnull, char *tdisp, int *status) +{ + ffgbcl(fptr, colnum, ttype, tunit, + dtype, repeat, tscal, tzero, + tnull, tdisp, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_read_img(fitsfile *fptr, int datatype, long firstelem, long nelem, + void *nulval, void *array, int *anynul, int *status) +{ + ffgpv(fptr, datatype, firstelem, nelem, + nulval, array, anynul, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_read_col( fitsfile *fptr, int datatype, int colnum, long firstrow, + long firstelem, long nelem, void *nulval, void *array, + int *anynul, int *status) +{ + ffgcv( fptr, datatype, colnum, firstrow, + firstelem, nelem, nulval, array, anynul, + status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_write_img(fitsfile *fptr, int datatype, long firstelem, long nelem, + void *array, int *status) +{ + ffppr(fptr, datatype, firstelem, nelem, + array, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_write_col(fitsfile *fptr, int datatype, int colnum, long firstrow, + long firstelem, long nelem, void *array, int *status) +{ + ffpcl(fptr, datatype, colnum, firstrow, + firstelem, nelem, array, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_insert_rows(fitsfile *fptr, long firstrow, long nrows, int *status) +{ + ffirow(fptr, firstrow, nrows, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_delete_rows(fitsfile *fptr, long firstrow, long nrows, int *status) +{ + ffdrow(fptr, firstrow, nrows, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_delete_rowlist(fitsfile *fptr, long *rownum, long nrows, int *status) +{ + ffdrws(fptr, rownum, nrows, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_insert_col(fitsfile *fptr, int numcol, char *ttype, char *tform, + int *status) +{ + fficol(fptr, numcol, ttype, tform, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_insert_cols(fitsfile *fptr, int firstcol, int ncols, char **ttype, + char **tform, int *status) +{ + fficls(fptr, firstcol, ncols, ttype, + tform, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_delete_col(fitsfile *fptr, int numcol, int *status) +{ + ffdcol(fptr, numcol, status); + cf_if_fits_error(*status); + return *status; +} + +int FITS_copy_col(fitsfile *infptr, fitsfile *outfptr, int incol, int outcol, + int create_col, int *status) +{ + ffcpcl(infptr, outfptr, incol, outcol, + create_col, status); + cf_if_fits_error(*status); + return *status; +} + diff --git a/src/libcf/cf_active_region.c b/src/libcf/cf_active_region.c new file mode 100644 index 0000000..8a3fd6e --- /dev/null +++ b/src/libcf/cf_active_region.c @@ -0,0 +1,90 @@ +/***************************************************************************** + * Johns Hopkins University + * Center For Astrophysical Sciences + * FUSE + ***************************************************************************** + * + * Synopsis: cf_active_region(fitsfile *header, long nevents, float *xfarf, + * float *yfarf, unsigned char *locflags) + * + * Description: Flags events outside of detector active area. + * + * Note: Both cf_ttag_init and cf_hist_init set LOCATION_SHLD + * when initializing IDF, but they look only at XRAW and use + * limits that are less restrictive than those used here. + * + * Arguments: fitsfile *header Pointer to FITS file containing the + * header of the intermediate data file + * long nevents The number of events + * float *xfarf An array of event X positions + * float *yfarf An array of event Y positions + * unsigned char *locflags Location flags of each event + * + * Calls: + * + * Return: 0 on success + * + * History: 11/12/02 1.1 peb Begin and finish work + * 03/11/03 1.2 wvd Changed locflags to unsigned char + * 05/20/03 1.3 rdr Added call to cf_proc_check + * 07/29/03 1.4 wvd If cf_proc_check fails, return errflg. + * 04/07/07 1.5 wvd Clean up compiler warnings. + * + ****************************************************************************/ + +#include +#include +#include "calfuse.h" + +int +cf_active_region(fitsfile *header, long nevents, float *xfarf, float *yfarf, + unsigned char *locflags) +{ + char CF_PRGM_ID[] = "cf_active_region"; + char CF_VER_NUM[] = "1.5"; + + char elecfile[FLEN_VALUE]={'\0'}; + char keyword[FLEN_KEYWORD]={'\0'}, detector[FLEN_VALUE]={'\0'}; + int errflg=0, status=0, active_l, active_r, active_b, active_t; + long j; + fitsfile *elecfits=NULL; + + cf_error_init(CF_PRGM_ID, CF_VER_NUM, stderr); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Begin Processing"); + + if ((errflg = cf_proc_check(header, CF_PRGM_ID))) return errflg; + + FITS_read_key(header, TSTRING, "DETECTOR", detector, NULL, &status); + /* + * Read keywords from ELEC_CAL file + */ + FITS_read_key(header, TSTRING, "ELEC_CAL", elecfile, NULL, &status); + FITS_open_file(&elecfits, cf_cal_file(elecfile), READONLY, &status); + sprintf(keyword, "ACTVL_%s", detector); + FITS_read_key(elecfits, TINT, keyword, &active_l, NULL, &status); + sprintf(keyword, "ACTVR_%s", detector); + FITS_read_key(elecfits, TINT, keyword, &active_r, NULL, &status); + sprintf(keyword, "ACTVB_%s", detector); + FITS_read_key(elecfits, TINT, keyword, &active_b, NULL, &status); + sprintf(keyword, "ACTVT_%s", detector); + FITS_read_key(elecfits, TINT, keyword, &active_t, NULL, &status); + FITS_close_file(elecfits, &status); + cf_verbose(3, "Active area limits: X from %d to %d, Y from %d to %d", + active_l, active_r, active_b, active_t); + /* + * Apply active region flags to each event. + */ + for(j=0; j active_r || + yfarf[j] < active_b || yfarf[j] > active_t) { + locflags[j] |= LOCATION_SHLD; + } + } + + cf_proc_update(header, CF_PRGM_ID, "COMPLETE"); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Done processing"); + return 0; +} diff --git a/src/libcf/cf_apply_dead_time.c b/src/libcf/cf_apply_dead_time.c new file mode 100644 index 0000000..a714a28 --- /dev/null +++ b/src/libcf/cf_apply_dead_time.c @@ -0,0 +1,142 @@ +/***************************************************************************** + * Johns Hopkins University + * Center For Astrophysical Sciences + * FUSE + ***************************************************************************** + * + * Synopsis: cf_apply_dead_time(fitsfile *header, long nevents, float *time, + * float *weight, long nseconds, float *timeline, + * float *ids_dtc, float *elec_dtc) + * + * Description: Applies dead-time correction to all photons. For HIST data, + * uses mean of dead-time arrays. Writes mean dead-time + * values to file header. Issue warning if DET_DEAD > 1.5. + * + * Arguments: fitsfile *header Pointer to FITS file containing the + * header of the intermediate data file + * long nevents The number of events + * float *time An array of event times + * float *weight An array of event weights + * long nseconds The number of timeline values + * float *timeline An array of timeline times + * float *aic_rate Active Image Counter rate + * float *ids_dtc Output of cf_ids_dead_time + * float *elec_dtc Output of cf_elec_dead_time + * + * Calls: + * + * Return: 0 on success + * + * History: 08/01/03 1.1 wvd Begin work + * 08/04/03 1.2 wvd Convert aic_rate to type short. + * 11/25/03 1.3 wvd For HIST data, require that + * mean_tot_dtc be >= 1. + * 11/26/03 1.4 wvd Change aic_rate to type float. + * 02/09/04 1.5 wvd Re-write with new logic. + * 04/09/04 1.6 bjg Include stdlib.h + * 11/07/05 1.7 wvd Add a test to catch bad DTC values. + * 03/10/06 1.8 wvd Clean up i/o. + * 12/29/06 1.9 wvd Check DET_DEAD rather than TOT_DEAD. + * 04/07/07 1.10 wvd Clean up compiler errors. + * + ****************************************************************************/ +#include +#include +#include "calfuse.h" + +int +cf_apply_dead_time(fitsfile *header, long nevents, float *time, float *weight, + long nseconds, float *timeline, float *ids_dtc, float *elec_dtc) +{ + char CF_PRGM_ID[] = "cf_apply_dead_time"; + char CF_VER_NUM[] = "1.10"; + + char comment[FLEN_CARD], datestr[FLEN_CARD], instmode[FLEN_VALUE]; + char hkexists[FLEN_VALUE]; + double ctimeb, ctimee, eng_time; + int errflg=0, status=0, timeref; + int det_flag=FALSE, ids_flag=FALSE; + long j, k; + float *tot_dtc, det_dead, ids_dead, mean_tot_dtc=0.; + + cf_error_init(CF_PRGM_ID, CF_VER_NUM, stderr); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Begin Processing"); + if ((errflg = cf_proc_check(header, CF_PRGM_ID))) return errflg; + + /* Read header keywords. Set flag if DET_DEAD > 1.5 */ + FITS_read_key(header, TSTRING, "INSTMODE", instmode, NULL, &status); + FITS_read_key(header, TSTRING, "HKEXISTS", hkexists, NULL, &status); + FITS_read_key(header, TFLOAT, "DET_DEAD", &det_dead, NULL, &status); + if (det_dead > 1.5) det_flag = TRUE; + + /* + * If there is no housekeeping file, AND the engineering snapshot times + * are bad, AND the mean value of any DTC array is > 1.5, set the + * combined DTC array to unity and issue a warning. + */ + if(!strncasecmp(hkexists, "N", 1)) { + FITS_read_key(header, TDOUBLE, "CTIME_B", &ctimeb, NULL, &status); + FITS_read_key(header, TDOUBLE, "CTIME_E", &ctimee, NULL, &status); + if ((eng_time = (ctimee-ctimeb) * 86400.) < 1.) { + FITS_read_key(header, TFLOAT, "IDS_DEAD", &ids_dead, NULL, &status); + if (ids_dead > 1.5) ids_flag = TRUE; + } + } + + /* + * Compute total dead-time correction and its mean. + */ + tot_dtc = (float *) cf_malloc(sizeof(float) * nseconds); + if (det_flag || ids_flag) { + for (k = 0; k < nseconds; k++) tot_dtc[k] = 1.0; + mean_tot_dtc = 1.0; + } + else { + for (k = 0; k < nseconds; k++) { + tot_dtc[k] = elec_dtc[k] * ids_dtc[k]; + mean_tot_dtc += tot_dtc[k]; + } + mean_tot_dtc /= nseconds; + } + + /* In TTAG mode, scale weights by tot_dtc as a function of time. */ + if (!strncmp(instmode, "TTAG", 4)) for (j=k=0; j 1.) + for (j = 0; j < nevents; j++) + weight[j] *= mean_tot_dtc; + else mean_tot_dtc = 1.; + + cf_verbose(2, "Mean total dead-time correction: %f", mean_tot_dtc); + FITS_update_key(header, TFLOAT, "TOT_DEAD", &mean_tot_dtc, NULL, &status); + + if (det_flag || ids_flag) { + FITS_write_comment(header, " ", &status); + if (ids_flag) { + sprintf(comment, + "IDS_DEAD > 1.5. Setting dead-time correction to unity."); + cf_if_warning(comment); + FITS_write_comment(header, comment, &status); + } + if (det_flag) { + sprintf(comment, + "DET_DEAD > 1.5. Setting dead-time correction to unity."); + cf_if_warning(comment); + FITS_write_comment(header, comment, &status); + } + fits_get_system_time(datestr, &timeref, &status); + sprintf(comment, "CalFUSE v%s %.10s", CALFUSE_VERSION, datestr); + FITS_write_comment(header, comment, &status); + FITS_write_comment(header, " ", &status); + } + + free (tot_dtc); + cf_proc_update(header, CF_PRGM_ID, "COMPLETE"); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Done processing"); + return 0; +} diff --git a/src/libcf/cf_apply_filters.c b/src/libcf/cf_apply_filters.c new file mode 100644 index 0000000..ff47f21 --- /dev/null +++ b/src/libcf/cf_apply_filters.c @@ -0,0 +1,177 @@ +/***************************************************************************** + * Johns Hopkins University + * Center For Astrophysical Sciences + * FUSE + ***************************************************************************** + * + * Synopsis: cf_apply_filters(fitsfile *header, int tscreen, long nevents, + * unsigned char *timeflags, unsigned char *loc_flags, + * long ntimes, unsigned char *gtiflags, + * float *dtime, float *ntime, long *ngood, long **index) + * + * Description: Select photons that satisfy filter criteria + * + * Arguments: fitsfile *header Pointer to FITS file containing the + * header of the intermediate data file + * int tscreen Flag indicating whether to screen on + * time flags (yes if > 0) + * long nevents The number of events + * unsigned char *timeflags Photon event time flags + * unsigned char *loc_flags Photon event location flags + * long ntimes Number of entries in timeline table + * unsigned char *gtiflags Status flags from timeline table + * float *dtime Day time exposure length + * float *ntime Night time exposure length + * long *ngood Number of good photons + * long **index List of good photon indexes + * + * Return: status + * + * History: 02/19/03 1.1 peb Begin work + * 03/20/03 1.2 peb Fixed daytime and nighttime + * calculation and fill header with + * correct EXPTIME and EXPNIGHT value. + * 04/08/03 1.3 wvd Get timeline-table arrays from + * calling routine. + * 05/10/03 1.4 wvd Read DAYNIGHT from file header; + * test only first character. + * 05/20/03 1.5 rdr Move to top level HDU before reading + * header keywords + * 06/09/03 1.6 rdr Ignore timing flags in the screening + * if tscreen is 0. + * 10/06/03 1.8 wvd Properly deal with new format of + * timeline table. + * 12/08/03 1.9 wvd If tscreen is 0, ignore temporal + * flags when calculating dtime & ntime. + * 02/11/04 1.10 wvd Correct error in calculation of + * dtime and ntime. + * 06/02/04 1.11 wvd Mask BRST, SAA, and LIMB flags + * when calculating exposure time + * for HIST data. + * 06/10/04 1.12 wvd Delete timeline times array from + * argument list. + * 01/27/05 1.13 wvd Use TEMPORAL_MASK rather than + * TEMPORAL_DAY to screen photon status + * flags. They differ only in HIST mode. + * 07/18/08 1.14 wvd If EXP_STAT = 2, target is bright + * earth or airglow. Mask limb-angle flag. + * 08/22/08 1.15 wvd Compare EXP_STAT with TEMPORAL_LIMB, + * rather than a particular value. + * + ****************************************************************************/ + +#include +#include +#include +#include "calfuse.h" + +int +cf_apply_filters(fitsfile *header, int tscreen, long nevents, + unsigned char *timeflags, unsigned char *loc_flags, + long ntimes, unsigned char *gtiflags, + long *dtime, long *ntime, long *ngood, long **index) +{ + char CF_PRGM_ID[] = "cf_apply_filters"; + char CF_VER_NUM[] = "1.15"; + + char daynight[FLEN_VALUE], instmode[FLEN_VALUE]; + int day=0, expstat, night=0, status=0; + long j; + float exptime; + unsigned char TEMPORAL_MASK; + + cf_error_init(CF_PRGM_ID, CF_VER_NUM, stderr); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Begin Processing"); + + /* + * Read INSTMODE keyword. If in HIST mode, mask out + * LIMB, SAA, and BRST flags. TEMPORAL_DAY is the default. + */ + TEMPORAL_MASK = TEMPORAL_DAY; + FITS_read_key(header, TSTRING, "INSTMODE", instmode, NULL, &status); + if (!strncmp(instmode, "HIST", 4)) { + TEMPORAL_MASK |= TEMPORAL_LIMB; + TEMPORAL_MASK |= TEMPORAL_SAA; + TEMPORAL_MASK |= TEMPORAL_BRST; + } + /* + * If EXP_STAT = TEMPORAL_LIMB, target is bright earth or airglow. + * Mask limb-angle flag. + */ + FITS_read_key(header, TINT, "EXP_STAT", &expstat, NULL, &status); + if (expstat == (int) TEMPORAL_LIMB) TEMPORAL_MASK |= TEMPORAL_LIMB; + + /* + * Calculate day/night exposure time. + * If tscreen is 0, ignore the temporal flags (other than day/night). + */ + *dtime = *ntime = 0.; + for (j=0; j exptime/10.) + cf_if_warning("Sum of day and night time differs from EXPTIME by > 10%%"); + + /* + * Apply screening to each photon event. + * First mask out airglow and day flags and test for zero + * (good) values. Next, see if the user wants daytime, + * night time, or both and confirm that appropriate flag is set. + */ + + *index = (long *) cf_calloc(nevents, sizeof(long)); + + if (tscreen) { + for(*ngood=j=0; j +#include +#include +#include "calfuse.h" + +static char CF_PRGM_ID[] = "cf_astig_farf"; +static char CF_VER_NUM[] = "1.9"; + + +/* + * Add astigmatism correction to XFARF for each photon within target + * aperture. Note that spectrum centroid moves with time. + */ +static int +farf_astig_shifts(fitsfile *header, long nevents, float *xfarf, + float *yfarf, unsigned char *channel, float *photon_time, + long nseconds, float *timeline_time, float *ycentl, float *ycents) +{ + char astig_file[FLEN_VALUE]; + int status=0; + int active_ap[2], ap, ast_cen, extno, overflow=0; + long i, j, k; + long npix, nx, ny, ii, jj, kk; + float yoff; + float *astig=NULL, *centroid=NULL; + fitsfile *astigfits; + + /* Read target apertures from the file header */ + (void) cf_source_aper (header, active_ap); + + /* Open the astigmatism file */ + FITS_read_key(header, TSTRING, "ASTG_CAL", astig_file, NULL, &status); + FITS_open_file(&astigfits, cf_cal_file(astig_file), READONLY, &status); + + /* Since we presently have no astig correction for extended + * sources, we apply correction only to target aperture. + */ + for (i = 0; i < 2; i++) { + + ap = active_ap[i]; + if (i == 0) + centroid = ycentl; + else + centroid = ycents; + + /* Read astigmatism correction for this aperture */ + extno = ap+1; + cf_verbose(3, "Reading extension %d of %s", extno, astig_file); + FITS_movabs_hdu(astigfits, extno, NULL, &status); + FITS_read_key(astigfits, TINT, "SLIT_CEN", &ast_cen, NULL, &status); + FITS_read_key(astigfits, TLONG, "NAXIS1", &nx, NULL, &status); + FITS_read_key(astigfits, TLONG, "NAXIS2", &ny, NULL, &status); + + npix = nx * ny; + astig = (float *) cf_malloc(sizeof(float) * npix); + FITS_read_img(astigfits, TFLOAT, 1L, npix, 0, astig, NULL, &status); + + /* Go through the photon list, find the astigmatism (delta(X)) + * corresponding to the (xfarf, yfarf) position and channel, + * and add it to xfarf[k]. + */ + k = 0; + for (j = 0; j < nevents; j++) { + if (channel[j] == ap) { + while ((photon_time[j] > timeline_time[k+1] - FRAME_TOLERANCE) + && (k < nseconds-1)) { + k++; + } + + /* Determine offset between spectrum and astig correction file. */ + yoff = centroid[k] - ast_cen; + + /* Find the astigmatism correction appropriate + to the photon's (xfarf, yfarf) position. */ + if ((ii = (xfarf[j] + 0.5)) >= nx) {overflow = 1; continue;}; + if ((jj = (yfarf[j] - yoff + 0.5)) >= ny) {overflow = 1; continue;} + if ((kk = jj * nx + ii) >= npix) {overflow = 1; continue;} + xfarf[j] += astig[kk]; + } + } + + /* If overflow flag is set, there is a problem with the ASTG_CAL file. */ + if (overflow) + cf_if_warning("Overflow of ASTG_CAL file in aperture %d", ap); + + /* Space for astig array is allocated in each loop. */ + free(astig); + } + + FITS_close_file(astigfits, &status); + return status; +} + +int cf_astig_farf(fitsfile *header, long nevents, float *xfarf, float *yfarf, + unsigned char *channel, float *photon_time, long nseconds, + float *timeline_time, float *ycentl, float *ycents) +{ + int errflg=0, status=0; + + /* Enter a timestamp into the log. */ + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Begin Processing"); + cf_error_init(CF_PRGM_ID, CF_VER_NUM, stderr); + + if ((errflg = cf_proc_check(header, CF_PRGM_ID))) return errflg; + + /* Check that astigmatism correction is appropriate for input image */ + if (astig_check_input_image(header) == 1) { + + /* Read astigmatism corrections for each aperture, add to XFARF */ + farf_astig_shifts(header, nevents, xfarf, yfarf, channel, + photon_time, nseconds, timeline_time, ycentl, ycents); + } + + /* Update processing flags. */ + cf_proc_update(header, CF_PRGM_ID, "COMPLETE"); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Done Processing"); + return (status); +} diff --git a/src/libcf/cf_astigmatism.c b/src/libcf/cf_astigmatism.c new file mode 100644 index 0000000..e02f361 --- /dev/null +++ b/src/libcf/cf_astigmatism.c @@ -0,0 +1,198 @@ +/***************************************************************************** + * Johns Hopkins University + * Center For Astrophysical Sciences + * FUSE + ***************************************************************************** + * + * Description: Modifies X array to correct for instrumental astigmatism. + * + * Since we have no astigmatism correction for extended + * sources, this program does not attempt to apply one. + * + * In keeping with the CalFUSE standard, the astigmatism + * correction is added to the measured X position of each photon. + * Versions of the ASTG_CAL file prior to v009 have the opposite + * sign and are incompatible with this version of the program. + * + * Returns: 0 upon successful completion. + * + * History: 12/02/02 1.1 jch Adapt from cf_astig.c + * 12/20/02 1.2 wvd Install + * 02/11/03 1.3 wvd Apply astig correction only if + * YCENT# > O for target aperture. + * Add ASTG_KEY keyword. Comment field: + * Performed? 1=LiF, 2=SiC, 3=Both + * 02/13/03 1.4 wvd Change all indices to type long. + * 02/24/03 1.5 peb Changed include file to calfusettag.h + * 03/04/03 1.6 peb Removed unused variables and math.h. + * Corrected sprintf:185 argument error. + * 03/11/03 1.7 wvd Change channel to type char + * 03/12/03 1.8 wvd If wavelength undefined, set + * channel[k] = 0 + * 04/04/03 1.9 wvd Test for overflow of astig array. + * 04/07/03 1.10 wvd Delete test for quality of YCENT. + * Delete ASTG_KEY keyword. + * Don't round yoff to nearest integer. + * 04/09/03 1.11 wvd Write name of ASTG_CAL file to trailer. + * 05/20/03 1.12 rdr Added call to cf_proc_check + * 09/16/03 1.13 wvd Change sign of ASTG_CAL file so that + * correction is additive. + * 09/22/03 1.14 wvd Initialize overflow counter. + * Print out number of overflows. + * 10/17/03 1.15 wvd Discard photons that fall outside of + * the astigmatism-correction window. + * 10/31/03 1.16 wvd Change channel to unsigned char. + * 11/11/03 1.17 wvd Interpolate between tabulated + * wavelength values. Use cf_read_col + * to read wavecal files. + * 02/17/04 1.18 wvd Replace cf_nint() with cf_nlong() + * 03/02/04 1.19 wvd Change name of assign_wavelengths + * to cf_x2lambda and make it + * generally accessible. + * 07/16/04 1.20 wvd Must change ASTG_COR to COMPLETE or + * SKIPPED by hand. + * 02/18/05 1.21 wvd Add some diagnostic output. + * 11/30/05 1.22 wvd Don't complain when photon events + * fall outside of astig images. + * 05/15/06 1.23 wvd Divide cf_astigmatism_and_dispersion + * into two separate routines. + * + ****************************************************************************/ + +#include +#include +#include +#include +#include "calfuse.h" + +static char CF_PRGM_ID[] = "cf_astigmatism"; +static char CF_VER_NUM[] = "1.23"; + + +/* + * Loop over the apertures, read appropriate astigmatism correction, + * and add to the input X shifts of pixels within extraction window. + */ +static int +add_astig_shifts(fitsfile *infits, long nevents, float *x, float *y, + unsigned char *channel) +{ + char astig_file[FLEN_VALUE], keyword[FLEN_VALUE]; + int status=0; + int ap, active_ap[2], ast_cen, extno, i, overflow; + long k, ii, jj, kk, npix, nx, ny; + float centroid, yoff; + float *astig=NULL; + fitsfile *astigfits; + + /* Read target apertures from the file header */ + (void) cf_source_aper (infits, active_ap); + + /* Open the astigmatism file */ + FITS_read_key(infits, TSTRING, "ASTG_CAL", astig_file, NULL, &status); + FITS_open_file(&astigfits, cf_cal_file(astig_file), READONLY, &status); + + /* Since we presently have no astig correction for extended + * sources, we apply correction only to target aperture. + */ + for (i = 0; i < 2; i++) { + ap = active_ap[i]; + + /* Read the centroid of the aperture from the input file. */ + sprintf(keyword, "YCENT%1d", ap); + FITS_read_key(infits, TFLOAT, keyword, ¢roid, NULL, &status); + cf_verbose(3, "Target aperture: %d\t Y centroid: %f", ap, centroid); + + /* Read astigmatism correction for this aperture */ + extno = ap+1; + cf_verbose(3, "Reading extension %d of %s", extno, astig_file); + FITS_movabs_hdu(astigfits, extno, NULL, &status); + FITS_read_key(astigfits, TINT, "SLIT_CEN", &ast_cen, NULL, &status); + FITS_read_key(astigfits, TLONG, "NAXIS1", &nx, NULL, &status); + FITS_read_key(astigfits, TLONG, "NAXIS2", &ny, NULL, &status); + + npix = nx * ny; + astig = (float *) cf_malloc(sizeof(float) * npix); + FITS_read_img(astigfits, TFLOAT, 1L, npix, 0, astig, NULL, &status); + + /* Determine offset between spectrum and astig correction file */ + yoff = centroid - ast_cen; + cf_verbose(3, "Offset between spectrum and astig correction: %f", yoff); + + /* Go through the event list and find the astigmatism correction + * appropriate for the photon's (x, y) position. + */ + overflow = 0; + for (k = 0; k < nevents; k++) { + if (channel[k] == ap) { + if (((ii = cf_nlong(x[k])) < 0 || ii >= nx) || + ((jj = cf_nlong(y[k] - yoff)) < 0 || jj >= ny) || + ((kk = jj * nx + ii) >= npix)) { + channel[k] = 0; + overflow++; + cf_verbose(3, "Cannot correct pixel %05ld (%f, %f)", + k, x[k], y[k]); + } + else x[k] += astig[kk]; + } + } + /* If overflow flag is set, there is a problem either with + the ASTG_CAL file or the input photon list. + if (overflow) + cf_if_warning("%d events fell outside of aperture %d ASTG_CAL window", + overflow, ap); + Comment this out, as it is always triggered by cf_bad_pixels. - wvd (11/30/05) */ + + /* Space for astig array is allocated in each loop. */ + free(astig); + cf_verbose(3, "End of loop for aperture %d", ap); + } + + FITS_close_file(astigfits, &status); + return status; +} + + +/* + * If APERTURE = RFPT or target is not a point source, exit without + * applying an astigmatism correction. + */ +int cf_astigmatism(fitsfile *infits, long nevents, float *x, + float *y, unsigned char *channel) +{ + char aperture[FLEN_VALUE]; + char source_type[FLEN_VALUE]; + int errflg=0, fileok=TRUE, status=0; + + /* Enter a timestamp into the log. */ + cf_error_init(CF_PRGM_ID, CF_VER_NUM, stderr); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Begin Processing"); + + if ((errflg = cf_proc_check(infits, CF_PRGM_ID))) return errflg; + + FITS_read_key(infits, TSTRING, "APERTURE", aperture, NULL, &status); + if (!strncmp(aperture, "RFPT", 4)) { + cf_verbose(1, "Aperture is RFPT. No astig correction applied."); + fileok = FALSE; + } + + /* Check source type */ + FITS_read_key(infits, TSTRING, "SRC_TYPE", source_type, NULL, &status); + if (strncmp(source_type, "P", 1)) { + cf_verbose(1, "Source type is %s. No astig correction applied.", + source_type); + fileok = FALSE; + } + + if (fileok) { + add_astig_shifts(infits, nevents, x, y, channel); + cf_proc_update(infits, CF_PRGM_ID, "COMPLETE"); + } + else + cf_proc_update(infits, CF_PRGM_ID, "SKIPPED"); + + /* Update processing flags. */ + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Done Processing"); + + return fileok; +} diff --git a/src/libcf/cf_cal_file.c b/src/libcf/cf_cal_file.c new file mode 100644 index 0000000..59c873d --- /dev/null +++ b/src/libcf/cf_cal_file.c @@ -0,0 +1,84 @@ +/***************************************************************************** + * Johns Hopkins University + * Center For Astrophysical Sciences + * FUSE + ***************************************************************************** + * + * Synopsis: cf_cal_file(char *calfile) + * + * Description: Returns a pointer to a string with the full calibration + * path (from the CF_CALDIR environment variable) prepended + * to the given file name. + * + * Arguments: char *calfile Name of the calibration file. + * + * Returns: A pointer to a string which contains the full path filename. + * + * History: 02/26/99 emurphy Begin and finish work. + * 03/01/99 emurphy Added some error checking + * 03/02/99 emurphy Added use of cf_if_warning + * 04/04/99 emurphy removed cf_error_init + * 04/08/99 barrett replaced fitsio.h with calfuse.h + * 05/18/99 emurphy Added checks on strlen and ending "/" + * 06/04/99 peb Removed 160 character string limit + * Added cf_malloc function. + * 08/05/99 emurphy Created cf_populate_file, to support + * cf_cal_file and cf_hist_file.c + * 08/25/99 emurphy Added cf_parm_file for parameter files. + * 12/18/03 bjg Change calfusettag.h to calfuse.h + * + ****************************************************************************/ + +#include +#include +#include "calfuse.h" + +static char +*cf_populate_file(char *calfile, char *enviro_name) +{ + char *enviro, *filen; + int strl, strt; + + enviro = getenv(enviro_name); + + if (enviro) { + strl = strlen(enviro); + strt = strl + strlen(calfile) + 16; + + filen = cf_malloc(strt); + strcpy(filen, enviro); + + /* Check to see if last character is a "/" */ + if (strncmp(filen+strl-1, "/", 1)!=0) + strcat(filen, "/"); + + strcat(filen, calfile); + return filen; + } + else { + printf("Environment variable %-20.20s undefined.",enviro_name); + cf_if_warning("Environment variable undefined"); + return calfile; + } +} + +char *cf_cal_file(char *calfile) +{ + + return cf_populate_file(calfile, "CF_CALDIR"); + +} + +char *cf_hist_file(char *calfile) +{ + + return cf_populate_file(calfile, "CF_HISTDIR"); + +} + +char *cf_parm_file(char *calfile) +{ + + return cf_populate_file(calfile, "CF_PARMDIR"); + +} diff --git a/src/libcf/cf_calculate_y_centroid.c b/src/libcf/cf_calculate_y_centroid.c new file mode 100644 index 0000000..ebcd264 --- /dev/null +++ b/src/libcf/cf_calculate_y_centroid.c @@ -0,0 +1,289 @@ +/************************************************************************** + * Johns Hopkins University + * Center for Astrophysical Sciences + * FUSE + ************************************************************************** + * + * Synopsis: cf_calculate_y_centroid(infits, nevents, weight, x, y, + * channel, timeflags, locflags) + * + * Description: Determines the y centroid of the target and airglow spectra + * in each aperture. The value written to the header depends + * on the quality flag for each channel in the IDF header. + * If QUALITY = HIGH, the target centroid is used; if MEDIUM, + * the airglow centroid is used; if LOW, the default centroid + * (from the CHID_CAL file) is used. + * + * Arguments: fitsfile infits Pointer to the input Intermediate Data File + * long nevents Number of photon events in the file + * float weight Scale factor for each photon + * float *x, *y X and Y positions of the photon + * unsigned char *channel Aperture associated with each photon + * unsigned char *timeflags Time flags - used to identify photons + * arriving during bursts, etc. + * unsigned char *locflags Location flags - used to identify photons + * in geocoronal line regions + * + * Calibration files required: + * + * Returns: 0 on success + * + * HISTORY: 10/16/02 v1.1 RDR started work + * 12/02/02 v1.2 RDR cleaned up variables + * 12/12/02 v1.3 wvd added include files + * 12/26/02 v1.4 RDR corrected error in calculating centroid + * 02/24/03 v1.5 peb changed include file to calfitsio.h + * 03/11/03 v1.6 wvd Changed screen to unsigned char + * 03/25/03 v1.7 rdr ignore pinhole aperture + * 04/03/03 v1.9 wvd Simplify calculation of centroid. + * Include airglow in centroid + * calculation of non-target apertures. + * Replace printf() with cf_verbose(). + * 04/17/03 v1.10 wvd Fix bug in calculation of non-target + * centroids. + * 04/18/03 v1.11 wvd Call cf_proc_update only if final_call + * is TRUE. Scale YCENT by photon weight + * for use with HIST data. Changed + * screen to locflags. + * 05/20/03 v1.12 rdr Added call to cf_proc_check + * 05/22/03 v1.14 wvd cf_error_init to stderr + * 08/21/03 v1.16 wvd Change channel to unsigned char + * 09/02/03 v1.17 bjg Now read user-specified centroid + * information from PARM_CAL and + * expected centroids from CHID_CAL. + * 09/02/03 v1.18 wvd Tidy up code. + * 09/17/03 v1.19 wvd Return -1 if a target centroid + * is too far from expected value. + * 10/28/03 v1.20 wvd Rewrite program with new logic. + * Delete use of final_call. + * 11/12/03 v1.21 wvd If no photons in channel, don't + * crash, just use default centroid. + * If quality = LOW, ygeo = ycent. + * 04/09/04 v1.22 bjg Include string.h and stdio.h + * 06/04/04 v1.23 wvd Use photon time flags to exclude + * bursts, etc. from calculation. + * 08/18/04 v1.24 wvd Test all spectra to see whether + * centroid is out of bounds. + * 03/11/05 v1.25 wvd Tabulate centroids as doubles, + * then convert to floats. + * Write target centroid values + * to trailer file if verbose >= 2. + * 04/15/05 v1.26 wvd Clean up i/o. + * 04/26/05 v1.27 wvd Don't populate YGEO keywords, as + * they are wrong for point sources. + * Consider only events with good + * LOCATION flags. + * Use the largest aperture with a valid + * YGEO to determine offset from tabulated + * position. Use this shift to calculate + * ygeo for the smaller apertures. + * 05/18/05 v1.28 wvd Test both SPEX_LIF and SPEX_SIC. + * Don't override user-specified centroid, + * even if it's far from expected value. + * Fix bug in tabulation of expected + * Y centroids. + * 02/01/06 v1.29 wvd If ycent is too far from default value, + * use default value, not airglow centroid. + * Allow computation of yshift from + * airglow photons in target aperture. + * 11/25/08 1.30 wvd In HIST mode, there are no spectra in + * other apertures to cause confusion, + * so we need not require that the target + * centroid lie within X pixels of either + * the airglow or tabulated centroid. + * + **************************************************************************/ + +#include +#include +#include +#include "calfuse.h" + +int cf_calculate_y_centroid(fitsfile *infits, long nevents, float *weight, + float *x, float *y, unsigned char *channel, unsigned char *timeflags, + unsigned char *locflags) +{ + + char CF_PRGM_ID[] = "cf_calculate_y_centroid"; + char CF_VER_NUM[] = "1.30"; + + char aperture[FLEN_VALUE], instmode[FLEN_VALUE]; + char ycentname[FLEN_KEYWORD], file_name[FLEN_VALUE]; + char key[FLEN_KEYWORD], quality[8][FLEN_VALUE]; + double dncent, dngeo, dycent, dygeo; + float ycent, ygeo, yshift, ycent_tab[8]; + int chan_num, errflg=0, status=0, active_ap[2]; + int got_shift, i, hdu, target_ap, user; + int spex_sic, spex_lif, emax_sic, emax_lif, emax, extended; + long n; + fitsfile *parm_cal, *chid_cal; + + /* Initialize error checking */ + cf_error_init(CF_PRGM_ID, CF_VER_NUM, stderr); + + /* Enter a time stamp into the log */ + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Begin Processing"); + + /* Check whether routine is appropriate for this data file. */ + if ( (errflg = cf_proc_check(infits, CF_PRGM_ID)) ) return errflg; + + /* Read the source aperture from the file header. */ + FITS_read_key(infits, TSTRING, "APERTURE", aperture, NULL, &status); + extended=cf_source_aper(infits, active_ap) ; + + /* Were data taken in HIST or TTAG mode? */ + FITS_read_key(infits, TSTRING, "INSTMODE", instmode, NULL, &status); + + /* Read centroid quality keywords from file header. */ + for (i = 1; i < 8; i++) { + if (i == 4) continue; + sprintf(key, "YQUAL%1d", i); + FITS_read_key(infits, TSTRING, key, &quality[i][0], NULL, &status); + } + + /* Read extraction parameters from PARM_CAL file. */ + FITS_read_key(infits, TSTRING, "PARM_CAL", file_name, NULL, &status); + FITS_open_file(&parm_cal, cf_parm_file(file_name), READONLY, &status); + FITS_read_key(parm_cal,TINT,"SPEX_SIC",&spex_sic,NULL,&status); + FITS_read_key(parm_cal,TINT,"SPEX_LIF",&spex_lif,NULL,&status); + FITS_read_key(parm_cal,TINT,"EMAX_SIC",&emax_sic,NULL,&status); + FITS_read_key(parm_cal,TINT,"EMAX_LIF",&emax_lif,NULL,&status); + FITS_close_file(parm_cal,&status); + + /* Read expected centroids from CHID_CAL file. Use extended-aperture + values except for apertures containing point-source targets. */ + FITS_read_key(infits, TSTRING, "CHID_CAL", file_name, NULL, &status); + FITS_open_file(&chid_cal, cf_cal_file(file_name), READONLY, &status); + for (i = 1; i < 8; i++) { + if (i==4) continue; + if ((i == active_ap[0] || i == active_ap[1]) && !extended) hdu=i+1; + else hdu=i+9; + FITS_movabs_hdu(chid_cal, hdu, NULL, &status); + FITS_read_key(chid_cal,TFLOAT,"CENTROID",ycent_tab+i,NULL,&status); + } + FITS_close_file(chid_cal,&status); + + /* Determine the centroids for each channel */ + yshift = 0; + got_shift = FALSE; + for (chan_num = 7; chan_num > 0; chan_num--) { + if (chan_num == 4) { + yshift = 0; + got_shift = FALSE; + continue; + } + dngeo = dncent = 0.; + dygeo = dycent = 0.; + sprintf (ycentname, "YCENT%d", chan_num); + + /* Is this a target aperture? */ + if (chan_num == active_ap[0] || chan_num == active_ap[1]) + target_ap = TRUE; + else + target_ap = FALSE; + + /* If not, and we're in histogram mode, skip to the next channel. */ + if (!target_ap && !strncmp(instmode, "HIST", 4)) continue; + + /* Calculate separate target and geocoronal centroids. */ + for (n = 0; n < nevents; n++) { + if (channel[n] == chan_num && !(timeflags[n] & ~TEMPORAL_DAY) && + !(locflags[n] & ~LOCATION_AIR)) { + + if(locflags[n] & LOCATION_AIR) { /* Airglow photon */ + dygeo += y[n] * weight[n]; + dngeo += weight[n]; + } + else { /* Target photon */ + dycent += y[n] * weight[n]; + dncent += weight[n]; + } + } + } + + /* If we can't find any photons but expect to, set quality to LOW. */ + if ((quality[chan_num][0] == 'H' && dncent < 1) || + (quality[chan_num][0] == 'M' && dngeo < 1)) { + quality[chan_num][0] = 'L'; + sprintf(key, "YQUAL%1d", chan_num); + FITS_update_key(infits, TSTRING, key, "LOW", NULL, &status) ; + cf_verbose(1, "No photon events in channel %d", chan_num); + } + + /* Compute centroids of target and airglow spectra */ + ycent = ygeo = 0; + if (dncent > 0) ycent = dycent / dncent; + if (dngeo > 0) ygeo = dygeo / dngeo; + + /* If yshift is already known, use it to calculate ygeo. + * If not, and ygeo is valid for this aperture, compute yshift. + */ + if (got_shift) + ygeo = yshift + ycent_tab[chan_num]; + else if (dngeo > 0) { + yshift = ygeo - ycent_tab[chan_num]; + got_shift = TRUE; + } + + /* Now decide which values to write to the header. */ + + /* If we are in the target aperture and the user has specified + * YCENT for this channel, use it. + */ + if (target_ap && ((chan_num<5 && spex_lif>=0 && spex_lif<1024) || + (chan_num>4 && spex_sic>=0 && spex_sic<1024))) { + if (chan_num<5) ycent=spex_lif; + else ycent=spex_sic; + cf_verbose(1, "Channel %d: User-specified Y centroid = %g", + chan_num, ycent); + user = TRUE; + } + else + user = FALSE; + + /* If the centroid quality is HIGH, use the calculated target + * value, regardless of whether we are in a target aperture. + * (This happens by default, so we don't have to do anything.) + */ + + /* If the centroid quality is MED, use the airglow centroid. */ + if (quality[chan_num][0] == 'M') + ycent = ygeo; + + /* If the quality is LOW, use the default value. */ + else if (quality[chan_num][0] == 'L') + ycent = ycent_tab[chan_num]; + + /* + * Test whether YCENT is too far from the expected value. + * If so, use the tabulated value and set the quality to LOW. + * Don't test HIST data. (wvd, 11/25/2008) + */ + if (chan_num<5) emax=emax_lif; else emax=emax_sic; + if (fabs(ycent-ycent_tab[chan_num]) > emax && !user && !strncmp(instmode, "TTAG", 4)) { + if(target_ap) { + cf_verbose(1, "Channel %d: computed centroid (%.1f) is too far " + "from expected value.", chan_num, ycent); + cf_verbose(1, "Channel %d: using default centroid of %.1f", + chan_num, ycent_tab[chan_num]); + } + else { + cf_verbose(2, "Channel %d: using default centroid of %.1f", + chan_num, ycent_tab[chan_num]); + } + ycent = ycent_tab[chan_num]; + sprintf(key, "YQUAL%1d", chan_num); + FITS_update_key(infits, TSTRING, key, "LOW", NULL, &status) ; + } + + /* Write centroid of target spectrum to the header */ + FITS_update_key(infits, TFLOAT, ycentname, &ycent, NULL, &status) ; + cf_verbose(2, "For channel %d, Y centroid = %.1f", chan_num, ycent) ; + + } /* End of loop over channels. */ + + cf_proc_update(infits, CF_PRGM_ID, "COMPLETE"); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Finished processing"); + + return status; +} diff --git a/src/libcf/cf_calculate_ycent_motion.c b/src/libcf/cf_calculate_ycent_motion.c new file mode 100644 index 0000000..8879213 --- /dev/null +++ b/src/libcf/cf_calculate_ycent_motion.c @@ -0,0 +1,152 @@ +/************************************************************************** + * Johns Hopkins University + * Center for Astrophysical Sciences + * FUSE + ************************************************************************* + * + * synopsis: cf_calculate_ycent_motion(header, nevents, ptime, y, channel, + * locflags, nsec, ttime, ycentl, ycents) + * + * Description: Determines the Y centroid of the emission as a function + * of time within the target apertures + * + * Arguments: fitsfile *header : pointer to Intermediate Data File + * long nevents : number of photon events in the file + * float *ptime : detection time for each photon + * float *y : y position of each photon + * unsigned char *channel: aperture associated with each photon + * unsigned char *locflags: location flag array + * long nsec : number of seconds tabulated in timeline + * float *ttime : tabulated times in the timeline + * geocoronal photons + * float *ycentl, *ycents : + * y centroids of the Lif and SiC apertures, + * tabulated once per second throughout + * the observation + * + * + * Calibration files required: None + * + * Returns: 0 on success + * + * + * HISTORY: 11/05/02 v1.1 RDR started work + * 11/27/07 v1.2 RDR corrected a bug in determining ycent + * cleaned up variables + * 12/04/02 v1.3 RDR locflags out geocoronal emission + * before determining centroids + * 12/12/02 v1.4 wvd change order of subroutine arguments + * 01/17/03 v1.5 wvd call cf_update_proc() + * 01/20/03 v1.6 rdr correct error in calculating ycent + * during the last time interval + * 02/24/03 v1.7 peb Changed include file to calfitsio.h + * 03/11/03 v1.8 wvd Changed locflags to unsigned char + * 05/20/03 v1.9 rdr Added call to cf_proc_check + * 05/22/03 v1.10 wvd cf_error_init to stderr + * 06/04/03 v1.11 wvd Implement cf_verbose throughout. + * 08/21/03 v1.12 wvd Change channel to unsigned char. + * 10/06/03 v1.13 wvd Change screen to locflags throughout. + * 10/21/04 v1.14 bjg Corrected several bugs + * 04/07/07 v1.15 wvd Clean up compiler warnings. + * 04/07/07 v1.16 wvd Clean up compiler warnings. + * + **************************************************************************/ + +#include "calfuse.h" + + +int +cf_calculate_ycent_motion(fitsfile *header, long nevents, float *ptime, + float *y, unsigned char *channel, unsigned char *locflags, + long nsec, float *ttime, float *ycentl, float *ycents) +{ + char CF_PRGM_ID[] = "cf_calculate_ycent_motion"; + char CF_VER_NUM[] = "1.16"; + + char ycentname[FLEN_CARD]; + int chan_num, status=0, j, src_type, active_ap[2], nave=500; + int errflg=0; + long i, ndx, ndxs, nsam; + float ycent, ptst, dt, dt1; + float ycentdef[2]; + float *ycentptr[2]; + + ycentptr[0]=ycentl; + ycentptr[1]=ycents; + + /* Initialize error checking */ + cf_error_init(CF_PRGM_ID, CF_VER_NUM, stderr); + + /* Enter a time stamp into the log */ + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Begin Processing"); + + /* Check whether routine is appropriate for this data file. */ + if ((errflg = cf_proc_check(header, CF_PRGM_ID))) return errflg; + + /* nave = number of photons to average in determining the centroid. + Should eventually be read from a parameter file. */ + nave = 500; + + /* Determine the source aperture and type from the header data. + src_type = 0 for a point source and 1 for an extended source. */ + + src_type = cf_source_aper(header, active_ap); + cf_verbose(3, "active_ap = %d and %d, src_type = %d", + active_ap[0], active_ap[1], src_type); + + + /* Determine the centroids. Do LiF and SiC apertures separately. */ + + for (j=0; j<2; j++) { + + + /* Select the channel number of the appropriate active aperture */ + chan_num = active_ap[j]; + sprintf(ycentname, "YCENT%1d", chan_num); + FITS_read_key(header, TFLOAT, ycentname, &ycentdef[j], NULL, &status); + + nsam = 0; + ycent = 0.; + ptst = ptime[0]; + ndxs = 0; + + /* Go through all of the photons, determine the y centroids, + and fill in the arrays. Avoid airglow lines. */ + for (i=1; i nave && dt > 1.) || i == nevents-1 || dt1 > 10) { + + if (nsam==0) ycent = ycentdef[j]; + else ycent = ycent / nsam; + + ndx = ndxs; + + while ( ndx < nsec && (ndx==0 || ttime[ndx-1] < ptime[i])) { + + if (nsam > nave) ycentptr[j][ndx] = ycent; + else { + if (ndx==0) ycentptr[j][ndx] = ycentdef[j]; + else ycentptr[j][ndx] = ycentptr[j][ndx-1]; + } + + + ndx += 1; + } + + ndxs=ndx; + if (ndxs > nsec-1) ndxs = nsec-1; + nsam = 0; + ycent=0.; + ptst=ptime[i]; + } + } + } + cf_proc_update(header, CF_PRGM_ID, "COMPLETE"); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Finished processing"); + return (status); +} diff --git a/src/libcf/cf_check_digitizer.c b/src/libcf/cf_check_digitizer.c new file mode 100644 index 0000000..81e9702 --- /dev/null +++ b/src/libcf/cf_check_digitizer.c @@ -0,0 +1,101 @@ +/***************************************************************************** + * Johns Hopkins University + * Center For Astrophysical Sciences + * FUSE + ***************************************************************************** + * + * Synopsis: cf_check_digitizer(fitsfile *infits); + * + * Description: Check the digitizer values against a reference file. + * + * Arguments: fitsfile *infits Input FITS file pointer + * + * Calls: + * + * Returns: 0 on success + * + * History: 01/16/03 1.1 jch Initial coding + * 01/28/03 1.2 wvd Check only values for this detector. + * 02/29/03 1.3 rch Correct error in making comparisons. + * 01/29/03 1.4 rdr Include math.h + * 03/04/03 1.5 peb Remove unused variables and header + * 05/20/03 1.6 rdr Add call to cf_proc_check + * 07/29/03 1.8 wvd If cf_proc_check fails, return errflg. + * 01/28/05 1.9 wvd On error, set EXP_STAT flag to -999 and + * issue a warning rather than an error. + * 03/11/05 1.10 wvd On error, write a warning to the file + * header using our standard format. + * 03/30/07 1.11 wvd On error, set EXP_STAT flag to -2, + * rather than -999. + * + ****************************************************************************/ + +#include +#include +#include "calfuse.h" + +#define N 32 + +int +cf_check_digitizer(fitsfile *infits) +{ + char CF_PRGM_ID[] = "cf_check_digitizer"; + char CF_VER_NUM[] = "1.11"; + + char comment[FLEN_COMMENT], datestr[FLEN_CARD], + file_name[FLEN_VALUE], detector[FLEN_VALUE]; + fitsfile *digifits; + int errflg=0, status=0, i, first, last, exp_stat = -2; + int timeref; + float val, ref_val; + + char key[N][9] = {"DET1ASCL", "DET1BSCL", "DET1AXOF", "DET1BXOF", "DET1AUCT", "DET1BUCT", "DET1ABWK", "DET1BBWK", "DET1AEWK", "DET1BEWK", "DET1ABSL", "DET1BBSL", "DET1ALCT", "DET1BLCT", "DET1ALTT", "DET1BLTT", "DET2ASCL", "DET2BSCL", "DET2AXOF", "DET2BXOF", "DET2AUCT", "DET2BUCT", "DET2ABWK", "DET2BBWK", "DET2AEWK", "DET2BEWK", "DET2ABSL", "DET2BBSL", "DET2ALCT", "DET2BLCT", "DET2ALTT", "DET2BLTT"}; + + cf_error_init(CF_PRGM_ID, CF_VER_NUM, stderr); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Begin Processing"); + + if ((errflg = cf_proc_check(infits, CF_PRGM_ID))) return errflg; + + /* + * Determine which detector produced our data file. + */ + FITS_read_key(infits, TSTRING, "DETECTOR", detector, 0, &status); + if (detector[0] == '1') + first = 0, last = N/2; + else + first = N/2, last = N; + + /* + * Read the digitizer reference file name and open it. + */ + FITS_read_key(infits, TSTRING, "DIGI_CAL", file_name, 0, &status); + FITS_open_file(&digifits, cf_cal_file(file_name), READONLY, &status); + + /* + * Read keywords. Compare with reference values. + */ + for (i = first; i < last; i++) { + FITS_read_key(infits, TFLOAT, key[i], &val, NULL, &status); + FITS_read_key(digifits, TFLOAT, key[i], &ref_val, NULL, &status); + + if (fabs(val - ref_val) > 2.0) { + cf_if_warning("Digitizer keyword %s is out of bounds.", key[i]); + sprintf(comment, "Data suspect: keyword %s out of bounds", key[i]); + FITS_update_key(infits, TINT, "EXP_STAT", &exp_stat, comment, + &status); + FITS_write_comment(infits, " ", &status); + sprintf(comment, "Data are suspect. Keyword %s is out of bounds.", + key[i]); + FITS_write_comment(infits, comment, &status); + fits_get_system_time(datestr, &timeref, &status); + sprintf(comment, "CalFUSE v%s %.10s", CALFUSE_VERSION, datestr); + FITS_write_comment(infits, comment, &status); + FITS_write_comment(infits, " ", &status); + } + } + + FITS_close_file(digifits, &status); + cf_proc_update(infits, CF_PRGM_ID, "COMPLETE"); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Done processing"); + return 0; +} diff --git a/src/libcf/cf_convert_to_ergs.c b/src/libcf/cf_convert_to_ergs.c new file mode 100644 index 0000000..2eaaeef --- /dev/null +++ b/src/libcf/cf_convert_to_ergs.c @@ -0,0 +1,182 @@ +/***************************************************************************** + * Johns Hopkins University + * Center For Astrophysical Sciences + * FUSE + ***************************************************************************** + * + * Synopsis: cf_convert_to_ergs(fitsfile *header, long nevents, + * float *weight, float *ergcm2, unsigned char *channel, + * float *lambda); + * + * Description: Convert counts to ergs. + * + * Arguments: *header Input FITS file pointer + * nevents number of points in the photon list + * *weight weight of each event + * *ergcm2 flux (returned) + * *channel channel number in the photon list + * *lambda wavelength in the photon list + * + * Returns: 0 (int) upon successful completion. + * + * History: 01/02/03 1.0 jch Initial coding + * 02/10/03 1.1 wvd Install + * 02/10/03 1.2 wvd Replace FLUX_CAL with AEFF_CAL + * Define HC in calfusettag.h + * Don't sort photons by wavelength + * 03/04/03 1.3 peb Fixed sprintf argument formating, + * deleted unused variable, localized + * scope of some variables, made sure + * that memory is allocated for aeff, + * and fixed memory leak with aeff, + * aeff1, and aeff2. + * 03/11/03 1.4 wvd Changed channel to type char + * 03/12/03 1.5 wvd Fixed bug in calculation of dl. + * If unable to calculate flux, + * set channel[k] = 0. + * Made aeff, aeff1, aeff2 doubles + * to match aeff*fit files. + * 05/07/03 1.6 wvd Change ERGCM2S to ERGCM2 throughout. + * Don't divide by EXPTIME. + * Use cf_verbose throughout. + * 05/16/03 1.7 wvd Update version number. + * 05/20/03 1.8 rdr Add call to cf_proc_check + * 06/11/03 1.9 wvd Pass datatype to cf_read_col. + * Change calfusettag.h to calfuse.h + * 08/25/03 1.10 wvd Change coltype from string to int + * in cf_read_col. + * 09/17/03 1.11 wvd Change aeff arrays to type float + * to match AEFF_CAL files. + * 11/05/03 1.12 wvd Change channel to unsigned char + * 04/27/04 1.13 wvd Print out relative weighting of + * the two effective-area files. + * 11/18/05 1.14 wvd Change aeff arrays to type double + * to match AEFF_CAL files. + * 04/07/07 1.15 wvd Clean up compiler warnings. + * 04/07/07 1.16 wvd Clean up compiler warnings. + * + ****************************************************************************/ + +#include +#include +#include +#include "calfuse.h" + +static char CF_PRGM_ID[] = "cf_convert_to_ergs"; +static char CF_VER_NUM[] = "1.16"; + + +int +cf_convert_to_ergs(fitsfile *header, long nevents, float *weight, + float *ergcm2, unsigned char *channel, float *lambda) +{ + char aeff1file[FLEN_VALUE], aeff2file[FLEN_VALUE]; + int ap, errflg=0, interp=0, status=0; + float sig1=0, sig2=0; + fitsfile *aeff1fits, *aeff2fits; + + /* Enter a timestamp into the log. */ + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Begin Processing"); + cf_error_init(CF_PRGM_ID, CF_VER_NUM, stderr); + + if ((errflg = cf_proc_check(header, CF_PRGM_ID))) return errflg; + + /* Read the AEFF1CAL and AEFF2CAL keywords. */ + FITS_read_key(header, TSTRING, "AEFF1CAL", aeff1file, NULL, &status); + FITS_read_key(header, TSTRING, "AEFF2CAL", aeff2file, NULL, &status); + + /* Open the calibration files. */ + FITS_open_file(&aeff1fits, cf_cal_file(aeff1file), READONLY, &status); + + /* Determine whether we need to interpolate getween AEFF_CAL files. */ + if (strcmp(aeff1file, aeff2file)) { + float dt1, dt2, dt3, a1date, a2date, expstart, expend, expmjd; + interp = 1; + FITS_open_file(&aeff2fits, cf_cal_file(aeff2file), READONLY, &status); + FITS_read_key(aeff1fits, TFLOAT, "EFFMJD", &a1date, NULL, &status); + FITS_read_key(aeff2fits, TFLOAT, "EFFMJD", &a2date, NULL, &status); + + /* Linearly interpolate the aeff according to exposure time */ + FITS_read_key(header, TFLOAT, "EXPSTART", &expstart, NULL, &status); + FITS_read_key(header, TFLOAT, "EXPEND", &expend, NULL, &status); + expmjd = (expstart + expend) / 2.; + dt1=a2date-a1date; + dt2=a2date-expmjd; + dt3=expmjd-a1date; + if (dt1 < 0.01) { + cf_if_error("Calibration file dates are identical: " + "cal1=%10.5f obs=%10.5f cal2=%10.5f", a1date, expmjd, a2date); + } + sig1=dt2/dt1; + sig2=dt3/dt1; + cf_verbose(3, "Interpolation: %0.2f x %s, %0.2f x %s", + sig1, aeff1file, sig2, aeff2file); + } + else + cf_verbose(3, "No interpolation. Using Aeff file %s", aeff1file); + + /* Step through the apertures, skipping aperture 4 (pinhole) */ + for (ap = 1; ap < 8; ap++) { + long jmax=0, /* size of wave and aeff arrays */ + j, /* index through wave and aeff */ + k; /* index through photon array */ + + double *aeff; + float *wavelength, dl, w0; + + if (ap == 4) + continue; + + if (interp == 1) { + /* Interpolate the calibrated aeff. */ + double *aeff1, *aeff2; + + FITS_movabs_hdu(aeff1fits, ap+1, NULL, &status); + jmax = cf_read_col(aeff1fits, TDOUBLE, "AREA", (void **) &aeff1); + + FITS_movabs_hdu(aeff2fits, ap+1, NULL, &status); + jmax = cf_read_col(aeff2fits, TDOUBLE, "AREA", (void **) &aeff2); + + aeff = (double *) cf_calloc(jmax, sizeof(double)); + + for (j = 0; j < jmax; j++) { + aeff[j] = sig1 * aeff1[j] + sig2 * aeff2[j]; + } + free(aeff1); + free(aeff2); + } else { + FITS_movabs_hdu(aeff1fits, ap+1, NULL, &status); + jmax = cf_read_col(aeff1fits, TDOUBLE, "AREA", (void **) &aeff); + } + + /* Read wavelength array in AEFF_CAL file */ + jmax = cf_read_col(aeff1fits, TFLOAT, "WAVE", (void **) &wavelength); + + /* Compute translation from wavelength to pixel within AEFF_CAL file. */ + w0 = wavelength[0]; + dl = (wavelength[jmax-1] - wavelength[0]) / (jmax - 1); + + /* Go through the photon list */ + for (k = 0; k < nevents; k++) { + if (channel[k] == ap) { + long j = (lambda[k] - w0) / dl + 0.5; + if (j >= 0L && j < jmax) + ergcm2[k] = weight[k]*HC/lambda[k]/aeff[j]; + else + channel[k] = 0; + } + } + free(wavelength); + free(aeff); + } + + /* Clean up. */ + FITS_close_file(aeff1fits, &status); + if (interp == 1) + FITS_close_file(aeff2fits, &status); + + /* Update processing flags. */ + cf_proc_update(header, CF_PRGM_ID, "COMPLETE"); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Done Processing"); + return (status); +} diff --git a/src/libcf/cf_count_rate_y_distort.c b/src/libcf/cf_count_rate_y_distort.c new file mode 100644 index 0000000..a42a4ac --- /dev/null +++ b/src/libcf/cf_count_rate_y_distort.c @@ -0,0 +1,157 @@ +/***************************************************************************** + * Johns Hopkins University + * Center For Astrophysical Sciences + * FUSE + ***************************************************************************** + * + * Synopsis: cf_count_rate_y_distort(fitsfile *header, long nevents, + * float *time, float *yfarf, + * unsigned char *locflags, long nseconds, + * float *timeline, float *fec_rate) + * + * Description: Corrects the Y position of each event based on the + * instantaneous count rate. + * + * Arguments: fitsfile *header Pointer to FITS file containing the + * header of the intermediate data file + * long nevents The number of events + * float *time An array of event times + * float *yfarf An array of event Y positions + * unsigned char *locflags Location flags for each event + * long nseconds The number of seconds in the timeline + * float *timeline The timeline in seconds + * float *fec_rate Front End Counter rate + * + * Calls: + * + * Return: 0 on success + * + * History: 08/06/02 1.1 peb Begin work + * 10/27/02 1.2 peb Added a time-dependent correction + * which uses the Front End Counter + * (FEC) rates. + * 11/11/02 1.3 peb Removed non-time-dependent correction. + * (Code now expects timeline extension + * data.) + * 11/11/02 1.4 peb Fixed compile error - added buffer + * variable. + * 11/12/02 1.5 peb Added check to move only events in + * active region. + * 03/11/03 1.6 wvd Changed locflags to unsigned char + * 05/20/03 1.7 rdr Added call to cf_proc_check + * 07/29/03 1.8 wvd If cf_proc_check fails, return errflg. + * 08/04/03 1.9 wvd Convert fec_rate to type short. + * 11/26/03 1.10 wvd Convert fec_rate to type float. + * 08/18/04 1.11 wvd Interpolate stretch correction among + * tabulated Y values. + * 10/06/05 1.12 wvd For HIST data, set each element of + * fec_rate to weighted mean of array. + * 04/07/07 1.13 wvd Clean up compiler warnings. + * + ****************************************************************************/ + +#include +#include +#include +#include "calfuse.h" + +int +cf_count_rate_y_distort(fitsfile *header, long nevents, float *time, + float *yfarf, unsigned char *locflags, long nseconds, + float *timeline, float *fec_rate) +{ + char CF_PRGM_ID[] = "cf_count_rate_y_distort"; + char CF_VER_NUM[] = "1.13"; + + char instmode[FLEN_VALUE], ystrfile[FLEN_VALUE]; + short xlen, ylen; + int errflg=0, hdutype, status=0, anynull=0; + int i, ii, i_max, rndx, yndx; + long j, k; + float *ystretch, ystr_1d[NYMAX], flt=0.; + fitsfile *ystrfits; + + cf_error_init(CF_PRGM_ID, CF_VER_NUM, stderr); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Begin Processing"); + + if ((errflg = cf_proc_check(header, CF_PRGM_ID))) return errflg; + + /* + * For HIST data, replace fec_rate with weighted mean value. + */ + FITS_read_key(header, TSTRING, "INSTMODE", instmode, NULL, &status); + if (!strncmp(instmode, "HIST", 4)) { + float *mean_rate, ratio, numerator=0, denominator=0; + mean_rate = (float *) cf_malloc(sizeof(float) * nseconds); + for (i = 0; i < nseconds; i++) { + numerator += fec_rate[i] * fec_rate[i]; + denominator += fec_rate[i]; + } + ratio = numerator / denominator; + for (i = 0; i < nseconds; i++) mean_rate[i] = ratio; + fec_rate = mean_rate; + cf_verbose(2, "Weighted mean count rate = %f", ratio); + } + + /* + * Read the rate calibration file. + */ + FITS_read_key(header, TSTRING, "RATE_CAL", ystrfile, NULL, &status); + FITS_open_file(&ystrfits, cf_cal_file(ystrfile), READONLY, &status); + FITS_movabs_hdu(ystrfits, 2, &hdutype, &status); + FITS_read_key(ystrfits, TSHORT, "NAXIS1", &xlen, 0, &status); + FITS_read_key(ystrfits, TSHORT, "NAXIS2", &ylen, 0, &status); + ystretch = (float *) cf_malloc(sizeof(float)*xlen*ylen); + FITS_read_img(ystrfits, TFLOAT, 1L, xlen*ylen, &flt, ystretch, &anynull, + &status); + FITS_close_file(ystrfits, &status); + + i_max = (xlen-1) * 10; + for(j=k=0; j= ylen) + rndx = ylen-1; + + /* + * This index reflects Y position on the detector. + * Shift information is provided for every 10 Y pixels. + * We interpolate to the nearest Y pixel. Otherwise, + * counts pile up at the 10-pixel boundaries. + */ + for (i = 0; i < i_max; i++) { + ii = (i/10) * 10; + ystr_1d[i] = ((ii+10-i) * (ystretch+rndx*xlen)[i/10] + + (i - ii) * (ystretch+rndx*xlen)[i/10+1]) / 10.; + } + for ( ; i < NYMAX; i++) + ystr_1d[i] = (ystretch+rndx*xlen)[xlen-1]; + } + + /* Now apply the shift. */ + yndx = (int) yfarf[j]; + if (yndx < 0) + yndx = 0; + else if (yndx >= NYMAX) + yndx = NYMAX-1; + yfarf[j] -= ystr_1d[yndx]; + } + } + free(ystretch); + if (!strncmp(instmode, "HIST", 4)) free(fec_rate); + + cf_proc_update(header, CF_PRGM_ID, "COMPLETE"); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Done processing"); + return 0; +} diff --git a/src/libcf/cf_dispersion.c b/src/libcf/cf_dispersion.c new file mode 100644 index 0000000..19a47c1 --- /dev/null +++ b/src/libcf/cf_dispersion.c @@ -0,0 +1,85 @@ +/***************************************************************************** + * Johns Hopkins University + * Center For Astrophysical Sciences + * FUSE + ***************************************************************************** + * + * Description: Assigns wavelength to each photon in data stream. + * + * Returns: 0 upon successful completion. + * + * History: 05/15/06 1.1 wvd Adapt from cf_astigmatism_and_dispersion.c + * Program incorporates cf_x2lambda. + * + ****************************************************************************/ + +#include +#include +#include +#include +#include "calfuse.h" + +static char CF_PRGM_ID[] = "cf_dispersion"; +static char CF_VER_NUM[] = "1.1"; + + +int +cf_dispersion(fitsfile *infits, long nevents, float *x, + unsigned char *channel, float *lambda) +{ + char wave_file[FLEN_VALUE]; + float *wavelength=NULL; + float x_lower, x_upper, weight_l, weight_u, wave_l, wave_u; + int ap, errflg=0, nwave, xl_int, xu_int, status=0; + long k; + fitsfile *wavefits; + + /* Enter a timestamp into the log. */ + cf_error_init(CF_PRGM_ID, CF_VER_NUM, stderr); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Begin Processing"); + + if ((errflg = cf_proc_check(infits, CF_PRGM_ID))) return errflg; + + FITS_read_key(infits, TSTRING, "WAVE_CAL", wave_file, NULL, &status); + FITS_open_file(&wavefits, cf_cal_file(wave_file), READONLY, &status); + + /* Cycle through channels, skipping #4 (pinhole) */ + for (ap = 1; ap < 8; ap++) { + if (ap == 4) continue; + + FITS_movabs_hdu(wavefits, ap+1, NULL, &status); + nwave = cf_read_col(wavefits, TFLOAT, "WAVELENGTH", (void **) &wavelength); + + /* Compute wavelength for each event by interpolation. */ + for (k = 0; k < nevents; k++) { + if (channel[k] == ap) { + x_lower = floor(x[k]); + x_upper = ceil(x[k]); + xl_int = (int) (x_lower + 0.5); + xu_int = (int) (x_upper + 0.5); + if (xl_int >= 0 && xu_int < nwave) { + if (xl_int == xu_int) + lambda[k] = wavelength[xl_int]; + else { + weight_l = x_upper - x[k]; + weight_u = x[k] - x_lower; + wave_l = wavelength[xl_int]; + wave_u = wavelength[xu_int]; + lambda[k] = wave_l * weight_l + wave_u * weight_u; + } + } + else + channel[k] = 0; + } + } + /* Space for wavelength array is allocated in each loop. */ + free(wavelength); + } + FITS_close_file(wavefits, &status); + + /* Update processing flags. */ + cf_proc_update(infits, CF_PRGM_ID, "COMPLETE"); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Done Processing"); + + return status; +} diff --git a/src/libcf/cf_doppler_and_heliocentric.c b/src/libcf/cf_doppler_and_heliocentric.c new file mode 100644 index 0000000..f95672d --- /dev/null +++ b/src/libcf/cf_doppler_and_heliocentric.c @@ -0,0 +1,87 @@ +/***************************************************************************** + * Johns Hopkins University + * Center For Astrophysical Sciences + * FUSE + ***************************************************************************** + * + * Synopsis: cf_doppler_and_heliocentric(*infits, nevents, *photon_time, + * *channel, *lambda, nseconds, *timeline_time, + * *timeline_velocity); + * + * Description: Doppler-correct each photon for both heliocentric and orbital + * motions. Resulting wavelength scale is heliocentric. + * + * Arguments: *infits Input FITS file pointer + * nevents number of points in the photon list + * *photon_time time array of photon events + * *channel channel number in the photon list + * *lambda wavelength in the photon list + * nseconds number of points in the timeline table + * *timeline_time time array of timeline list + * *timeline_velocity orbital velocity in km/s + * + * Returns: O upon successful completion + * + * History: 12/09/2002 jch 1.1 Initial coding + * 12/11/2002 wvd 1.2 Move Doppler calculation to separate + * loop. + * 12/11/2002 wvd 1.3 Change nevents and nseconds to long. + * 12/20/2002 wvd 1.4 Change channel to unsigned char. + * 02/24/03 peb 1.5 Change include file to calfusettag.h + * and calfitsio.h + * 03/11/2003 wvd 1.6 Change channel to char. + * 05/20/2003 rdr 1.7 Added call to cf_proc_check + * 09/17/2003 wvd 1.8 Return errflg from cf_prock_check + * 10/21/2003 wvd 1.9 Change channel to unsigned char. + * 04/21/2004 bjg 1.10 Cosmetic change to prevent warning + * with gcc -Wall + * 11/17/2005 wvd 1.11 Change velocity and doppler to doubles. + * + ****************************************************************************/ + +#include +#include "calfuse.h" + +char CF_PRGM_ID[] = "cf_doppler_and_heliocentric"; +char CF_VER_NUM[] = "1.11"; + + +int cf_doppler_and_heliocentric(fitsfile *infits, long nevents, + float *photon_time, unsigned char *channel, float *lambda, + long nseconds, float *timeline_time, float *timeline_velocity) +{ + int errflg=0, status=0; + long i, k; + float v_helio; /* heliocentric velocity in km/sec */ + double velocity, *doppler; + + /* Enter a timestamp into the log. */ + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Begin Processing"); + cf_error_init(CF_PRGM_ID, CF_VER_NUM, stderr); + + if ((errflg = cf_proc_check(infits, CF_PRGM_ID) )) return errflg; + + FITS_read_key(infits, TFLOAT, "V_HELIO", &v_helio, NULL, &status); + + /* Compute array of Doppler corrections. */ + doppler = (double *) cf_malloc(sizeof(double) * nseconds); + for (k = 0; k < nseconds; k++) { + velocity = timeline_velocity[k] + v_helio; + doppler[k] = 1. + velocity / C; + } + + /* Apply Doppler correction to each photon assigned to an aperture. */ + k = 0; + for (i = 0; i < nevents; i++) + if (channel[i] > 0) { + while (photon_time[i] > timeline_time[k+1] - FRAME_TOLERANCE + && k < nseconds-1) k++; + lambda[i] *= doppler[k]; + } + free (doppler); + + /* Update processing flags. */ + cf_proc_update(infits, CF_PRGM_ID, "COMPLETE"); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Done Processing"); + return (status); +} diff --git a/src/libcf/cf_electronics_dead_time.c b/src/libcf/cf_electronics_dead_time.c new file mode 100644 index 0000000..38c2219 --- /dev/null +++ b/src/libcf/cf_electronics_dead_time.c @@ -0,0 +1,104 @@ +/***************************************************************************** + * Johns Hopkins University + * Center For Astrophysical Sciences + * FUSE + ***************************************************************************** + * + * Synopsis: cf_electronics_dead_time(fitsfile *header, long nseconds, + * float *fec_rate, float *elec_dtc) + * + * Description: Scales the weighting factor to correct for the electronics + * dead time. + * + * Arguments: fitsfile *header Pointer to FITS file containing the + * header of the intermediate data file + * long nseconds The number of timeline values + * float *fec_rate An array of Front End Counter (FEC) + * rates + * float *elec_dtc Dead-time correction array (returned) + * Calls: + * + * Return: 0 on success + * + * History: 10/27/02 1.1 peb Begin work + * 11/11/02 1.2 peb Corrected function description and + * added cf_timestamp after ELEC_COR + * check. + * 12/06/02 1.4 wvd Calculate DT correction for each time + * step, then apply to photons. + * Set keyword DET_DEAD. + * 05/20/03 1.5 rdr Added proc_check call + * 08/01/03 1.7 wvd Just calculate correction; don't + * apply it. Return elec_dtc array. + * 08/04/03 1.8 wvd Convert fec_rate to type short. + * 11/26/03 1.9 wvd Change fec_rate to type float. + * 02/12/04 1.10 wvd In verbose mode, write mean DTC. + * 04/07/07 1.11 wvd Clean up compiler warnings. + * + ****************************************************************************/ + +#include +#include +#include "calfuse.h" + +int +cf_electronics_dead_time(fitsfile *header, long nseconds, + float *fec_rate, float *elec_dtc) +{ + char CF_PRGM_ID[] = "cf_electronics_dead_time"; + char CF_VER_NUM[] = "1.11"; + + char elecfile[FLEN_VALUE]={"\0"}, detector[FLEN_VALUE]={"\0"}; + char keyword[FLEN_KEYWORD]={"\0"}; + int errflg=0, status=0; + long k; + float abort, clock, state; + float mean_elec_dtc = 0.; + fitsfile *elecfits; + + cf_error_init(CF_PRGM_ID, CF_VER_NUM, stderr); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Begin Processing"); + + if ((errflg = cf_proc_check(header, CF_PRGM_ID))) return errflg; + + FITS_read_key(header, TSTRING, "DETECTOR", detector, NULL, &status); + /* + * Get the electronics dead-time constants. + */ + FITS_read_key(header, TSTRING, "ELEC_CAL", elecfile, NULL, &status); + FITS_open_file(&elecfits, cf_cal_file(elecfile), READONLY, &status); + sprintf(keyword, "ABORT_%s", detector); + FITS_read_key(elecfits, TFLOAT, keyword, &abort, NULL, &status); + sprintf(keyword, "CLOCK_%s", detector); + FITS_read_key(elecfits, TFLOAT, keyword, &clock, NULL, &status); + sprintf(keyword, "STATE_%s", detector); + FITS_read_key(elecfits, TFLOAT, keyword, &state, NULL, &status); + FITS_close_file(elecfits, &status); + /* + * Calculate dead-time correction. + */ + for (k=0; k=2 prints only message. + * 10/30/03 1.5 peb Replaced cftime function with strftime + * for UNIX compatibility. + * Removed unnecessary header files, + * malloc.h and unistd.h + * 04/07/04 1.6 bjg fflush stdout and error_file + * + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "fitsio.h" + +#define N_STYM 40 + +int verbose_level=0; + +static char *program_name=NULL; +static char *version_no=NULL; +static FILE *error_file=NULL; + +void cf_error_init(const char *progid, const char *vernum, FILE *errfile) +{ + static char unknown[] = "unknown file"; + static char version[] = "1.6"; + if (progid) { + program_name = malloc(strlen(progid)+1); + strcpy(program_name, progid); + } + else { + program_name = malloc(strlen(unknown)+1); + strcpy(program_name, unknown); + } + if (vernum) { + version_no = malloc(strlen(vernum)+1); + strcpy(version_no, vernum); + } + else { + version_no = malloc(strlen(version)+1); + strcpy(version_no, version); + } + if (errfile) + error_file = errfile; + else + error_file = stderr; +} + +void cf_verbose(int level, const char *format, ...) +{ + va_list args; + va_start(args, format); + + if (verbose_level >= level) { + if (level == 1) + printf(" %s-%s: ", program_name, version_no); + else if (level >= 2) + printf("\t"); + vprintf(format, args); + printf("\n"); + fflush(stdout); + } + + va_end(args); +} + +void cf_if_warning(char *format, ...) +{ + char stym[N_STYM]={'\0'}; + time_t tym; + va_list args; + + va_start(args, format); + time(&tym); + strftime(stym, N_STYM, "%Y %b %e %T", localtime(&tym)); + + fprintf(error_file, "%s %s-%s: WARNING - ", + stym, program_name, version_no); + vfprintf(error_file, format, args); + fprintf(error_file, "\n"); + fflush(error_file); + va_end(args); +} + +void cf_if_error(char *format, ...) +{ + char stym[N_STYM]={'\0'}; + time_t tym; + va_list args; + + va_start(args, format); + time(&tym); + strftime(stym, N_STYM, "%Y %b %e %T", localtime(&tym)); + + fprintf(error_file, "%s %s-%s: ERROR - ", + stym, program_name, version_no); + vfprintf(error_file, format, args); + fprintf(error_file, "\n"); + + fflush(error_file); + va_end(args); + exit(1); +} + +void cf_if_fits_warning(int status) +{ + if (status) { + char stym[N_STYM]={'\0'}; + time_t tym; + + time(&tym); + strftime(stym, N_STYM, "%Y %b %e %T", localtime(&tym)); + + fprintf(error_file, "%s %s-%s: FITS WARNING - ", + stym, program_name, version_no); + fits_report_error(error_file, status); + fflush(error_file); + } +} + +void cf_if_fits_error(int status) +{ + if (status) { + char stym[N_STYM]={'\0'}; + time_t tym; + + time(&tym); + strftime(stym, N_STYM, "%Y %b %e %T", localtime(&tym)); + + fprintf(error_file, "%s %s-%s: FITS ERROR - ", + stym, program_name, version_no); + fits_report_error(error_file, status); + fflush(error_file); + exit(1); + } +} + +void *cf_malloc(size_t size) +{ + void *ptr; + + if (!(ptr = malloc(size))) { + char stym[N_STYM]={'\0'}; + time_t tym; + + time(&tym); + strftime(stym, N_STYM, "%Y %b %e %T", localtime(&tym)); + + fprintf(error_file, "%s %s-%s: ERROR - %s\n", + stym, "cf_malloc", "1.0", strerror(errno)); + + fflush(error_file); + exit(1); + /* + fprintf(error_file, + " \n malloc: Attemping to allocate %d bytes", size); + */ + } + return ptr; +} + +void *cf_calloc(size_t nelem, size_t elsize) +{ + void *ptr; + + if (!(ptr = calloc(nelem, elsize))) { + char stym[N_STYM]={'\0'}; + time_t tym; + + time(&tym); + strftime(stym, N_STYM, "%Y %b %e %T", localtime(&tym)); + + fprintf(error_file, "%s %s-%s: ERROR - %s\n", + stym, "cf_calloc", "1.0", strerror(errno)); + + fflush(error_file); + exit(1); + /* + fprintf(error_file, + " \n calloc: Attemping to allocate %d bytes", + nelem * elsize); + */ + } + return ptr; +} + +void cf_if_memory_error(int status) +{ + time_t tym; + + if (!status) { + time(&tym); + fprintf(error_file, "Memory allocation error in %s-%s: %s", + program_name, version_no, ctime(&tym)); + + /* Print out cfitsio error messages and continue */ + + fits_report_error(error_file, status); + fflush(error_file); + } +} + +/* +int main() +{ + int i; + cf_error_init("test program", "1.0", stdout); + cf_if_warning("Non-fatal error occurred"); + + for (i=0; i < 10; i++) + cf_if_fits_warning(i); + exit(0); +} +*/ diff --git a/src/libcf/cf_extraction_limits.c b/src/libcf/cf_extraction_limits.c new file mode 100644 index 0000000..5567d14 --- /dev/null +++ b/src/libcf/cf_extraction_limits.c @@ -0,0 +1,137 @@ +/***************************************************************************** + * Johns Hopkins University + * Center For Astrophysical Sciences + * FUSE + ***************************************************************************** + * + * Synopsis: cf_extraction_limits(fitsfile *infits, int aperture, + * int srctype, short **ylow, short **yhigh, short *xmin, + * short *xmax) + * + * Description: Read the extraction limits for a given aperture and source + * type (point or extended) from the CHID_CAL file. Shift these + * limits to match the centroid of the observed spectrum, if + * that measurement has been performed. For point sources + * observed in HIST mode, pad YLOW and YHIGH by SPECBINY pixels. + * + * Arguments: fitsfile *infits Pointer to the location of the FITS + * header of the Intermediate Data File + * int aperture aperture designation (1 through 8) + * int srctype 0 = point source, 1 = extended + * short **ylow lower Y bound for the extraction window + * short **yhigh upper Y bound for the extraction window + * short *xmin lower X bound for the extraction window + * short *xmax upper X bound for the extraction window + * + * Calls: None + * + * Return: npts = length of arrays ylow and yhigh + * + * History: 08/22/03 1.1 BJG Based on subroutine from v1.6 of + * cf_bad_pixels.c by RDR. + * Change coltype from char to int in + * cf_read_col. + * 03/15/05 1.2 wvd Read HIST_PAD from appropriate HDU + * of CHID_CAL file and pad apertures + * if data are in HIST mode. + * 03/16/05 1.3 wvd For extended sources, return large + * apertures. + * 10/06/05 1.4 wvd Always pad apertures by 8 pixels + * in HIST mode. + * 05/03/06 1.5 wvd Always pad apertures by SPECBINY + * pixels in HIST mode. + * + ****************************************************************************/ + +#include +#include +#include +#include "calfuse.h" + +long cf_extraction_limits(fitsfile *infits, int aperture, int srctype, + short **ylow, short **yhigh, short *xmin, short *xmax) { + + char CF_PRGM_ID[] = "cf_extraction_limits"; + char CF_VER_NUM[] = "1.5"; + + fitsfile *chidfits ; + int status=0, hdutype; + int dcent, hdu ; + short histpad=0, specbiny; + short xmint, xmaxt, *ylowt=NULL, *yhight=NULL; + float ycent_data, ycent_tab ; + long j, npts ; + char ycentname[FLEN_VALUE]={'\0'}, chidfile[FLEN_VALUE] ; + char instmode[FLEN_VALUE]; + + cf_error_init(CF_PRGM_ID, CF_VER_NUM, stderr); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Begin Processing"); + + /* Read the measured centroid from the input file header. */ + FITS_movabs_hdu(infits, 1, &hdutype, &status) ; + sprintf(ycentname,"YCENT%1d",aperture) ; + FITS_read_key(infits, TFLOAT, ycentname, &ycent_data, NULL, &status); + cf_verbose(3, "Reading extraction limits for aperture %d ", aperture) ; + cf_verbose(3, "ycent keyword = %s, value=%5.1f ", ycentname, ycent_data) ; + + /* Read instrument mode and binning factor from file header. */ + FITS_read_key(infits, TSTRING, "INSTMODE", instmode, NULL, &status); + FITS_read_key(infits, TSHORT, "SPECBINY", &specbiny, NULL, &status); + + /* Which HDU to read depends on both channel and source type. */ + hdu = aperture + 1; + if (srctype) hdu += 8; + + /* Open the CHID_CAL file. */ + FITS_read_key(infits, TSTRING, "CHID_CAL", chidfile, NULL, &status); + cf_verbose(3, "spectral extraction file = %s, HDU = %d", chidfile, hdu); + FITS_open_file(&chidfits, cf_cal_file(chidfile), READONLY, &status); + FITS_movabs_hdu(chidfits, hdu, &hdutype, &status); + + /* Read X limits of extraction window. */ + FITS_read_key(chidfits, TSHORT, "XMIN", &xmint, NULL, &status); + FITS_read_key(chidfits, TSHORT, "XMAX", &xmaxt, NULL, &status); + + /* Read centroid of tabulated extraction window. */ + FITS_read_key(chidfits,TFLOAT,"CENTROID",&ycent_tab,NULL,&status); + + /* For point-source data taken in HIST mode, pad window. */ + if ((!strncmp(instmode, "HIST", 4)) && !srctype) histpad = specbiny; + /* FITS_read_key(chidfits,TSHORT,"HIST_PAD",&histpad,NULL,&status); */ + + /* Read the upper and lower boundaries of the extraction slit. */ + npts=cf_read_col(chidfits, TSHORT, "YLOW", (void **) &ylowt); + npts=cf_read_col(chidfits, TSHORT, "YHIGH", (void **) &yhight); + FITS_close_file(chidfits, &status) ; + + /* If the spectral centroid has been measured, shift the aperture + limits so that the tabulated centroid equals the measured value. */ + if (ycent_data > 1 && ycent_data < NYMAX) { + dcent = (short) cf_nint(ycent_data - ycent_tab) ; + cf_verbose(3, "shifting extraction window: ycent_tab=%5.1f, delta=%d", + ycent_tab, dcent) ; + for (j = xmint; j <= xmaxt; j++) { + ylowt[j] += dcent ; + yhight[j] += dcent ; + } + } + + /* If HIST_PAD > 0, pad the extraction window, top and bottom. */ + if (histpad > 0) { + cf_verbose(3, "HIST point source. " + "Padding extraction window by +/- %d pixels", histpad); + for (j = xmint; j <= xmaxt; j++) { + ylowt[j] -= histpad ; + yhight[j] += histpad ; + } + } + + /* Return the extraction limits. */ + *xmin = xmint; + *xmax = xmaxt; + *ylow = ylowt ; + *yhigh = yhight ; + + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Done processing"); + return npts ; +} diff --git a/src/libcf/cf_fes_proc_check.c b/src/libcf/cf_fes_proc_check.c new file mode 100644 index 0000000..74a41b4 --- /dev/null +++ b/src/libcf/cf_fes_proc_check.c @@ -0,0 +1,94 @@ +/****************************************************************************** + * Johns Hopkins University + * Center For Astrophysical Sciences + * FUSE + ****************************************************************************** + * + * Synopsis: cf_fes_proc_check(fitsfile *fptr, char *prog_id) + * + * Description: cf_fes_proc_check will determine if a given calibration + * step is to be performed on the data. It will also + * determine whether all previous steps have been + * completed successfully. + * + * Arguments: fitsfile *fptr Pointer to input file + * char *prog_id Procedure name + * + * History: 06/21/98 emm Begin work. + * 08/19/2004 1.1 wvd Move to v3.0, add CF_VER_NUM, + * change cf_errmsg to cf_if_error. + * 09/07/2007 1.2 bot Removed unused CF_VER_NUM and CF_PRGM_ID + * + *****************************************************************************/ + +#include +#include +#include "calfuse.h" +#define MAXCHARS 120 + +int cf_fes_proc_check(fitsfile *fptr, char *prog_id) +{ + int i,j, status=0; + char comment[FLEN_CARD], key_value[FLEN_CARD]; + char complete[19], skipped[19], perform[19]; + + /* + * The calfuse.h file contains the definitions of fes_keyword_tab + * NUM_PROC_STEPS, and CALIBRATION_STEP_KEYS. + */ + struct fes_keyword_tab keytab[NUM_FES_PROC_STEPS]=FES_CALIBRATION_STEP_KEYS; + status=0; + + strncpy(complete,"COMPLETE ",19); + strncpy(skipped, "SKIPPED ",19); + strncpy(perform, "PERFORM ",19); + + j=0; + /* + * First, determine if this procedure is even supposed to be + * run on this data. + */ + while ((strncmp(keytab[j].proc,prog_id, strlen(keytab[j].proc)) != 0) && + (j < NUM_FES_PROC_STEPS)) j++; + if ((j >= NUM_FES_PROC_STEPS) || + (strncmp(keytab[j].value,perform,7))) { + cf_if_error("Processing step does not " + "need to be run on this type of data."); + fprintf(stderr," Step %18.18s does not need " + "to be run.\n",prog_id); + return 1; + } + + status=0; + fits_read_key_str(fptr, keytab[j].name, key_value, comment, + &status); + + /* Now check to see if the step has already been completed. */ + if (strncmp(key_value,complete,7)==0) { + cf_if_error("Processing step has already been completed.\n"); + fprintf(stderr," Step %18.18s does not need to be run.\n", + prog_id); + return 1; + } + + /* Now determine if the previous programs are all complete. */ + for (i=0; i +#include +#include "calfuse.h" + +int cf_fes_proc_update(fitsfile *fptr, char *prgm_id, char *key_value) +{ + int i=0, status=0; + /* + * The calfuse.h file contains the definitions of fes_keyword_tab + * NUM_FES_PROC_STEPS, and FES_CALIBRATION_STEP_KEYS. + */ + struct fes_keyword_tab keytab[NUM_FES_PROC_STEPS]=FES_CALIBRATION_STEP_KEYS; + /* + * Find the keyword associated with prgm_id by looping + * through keytab[i].proc + */ + while ((strncmp(keytab[i].proc,prgm_id, strlen(keytab[i].proc)) != 0) && + (i < NUM_FES_PROC_STEPS)) i++; + if (i < NUM_FES_PROC_STEPS) { + /* + * We found a match to prgm_id, so change the associated + * keyword in the header. + */ + fits_modify_key_str(fptr,keytab[i].name,key_value, + "&",&status); + if (status) { + cf_if_error("Error updating keyword"); + return status; + } + } + else { + /* + * The given prgm_id did not match any of the known + * keytab[i].hist_proc, so return 1. + */ + cf_if_error("Program ID does not apply to this" + "type of file, could not update"); + fprintf(stderr,"Failed to update program id:%20.20s\n", + prgm_id); + return 1; + } + return status; +} diff --git a/src/libcf/cf_fifo_dead_time.c b/src/libcf/cf_fifo_dead_time.c new file mode 100644 index 0000000..67ac065 --- /dev/null +++ b/src/libcf/cf_fifo_dead_time.c @@ -0,0 +1,164 @@ +/***************************************************************************** + * Johns Hopkins University + * Center For Astrophysical Sciences + * FUSE + ***************************************************************************** + * + * Synopsis: cf_fifo_dead_time(fitsfile *header, long nevents, + * float *ptime, long nseconds, float *ttime, float *aic_rate, + * float *ids_dtc) + * + * Description: Searches high-count-rate observations for data drop-outs + * due to FIFO overflows. If found, calculates time-dependent + * scale factor to correct for lost photon events. + * + * Arguments: fitsfile *header Pointer to FITS file containing the + * header of the intermediate data file + * long nevents Number of photon events in the file + * float *ptime Detection time for each photon + * long nseconds The number of timeline values + * float *ttime Tabulated times in the timeline + * float *aic_rate Active Image Counter array + * float *ids_dtc IDS dead-time correction array + * (modified) + * + * Calls: + * + * Return: 0 on success + * + * History of cf_screen_fifo_overflow: + * + * 02/10/04 1.1 wvd Begin work + * 02/17/05 1.2 wvd Place parentheses around assignment + * used as truth value. + * 11/09/05 1.3 wvd In the current scheme, the rate_lif + * and rate_sic arrays contain values + * from the housekeeping file and do + * not reflect data loss due to FIFO + * overflows. Now we calculate the + * count-rate array directly from the + * photon time array. + * 02/23/06 1.4 wvd Change length of data_rate array + * from nevents to nseconds. + * + * History: 12/29/06 1.1 wvd Derived from cf_screen_fifo_overflow. + * 01/15/07 1.2 wvd When count rate is zero, correct one + * second before to two seconds after. + * 02/08/07 1.3 wvd If TTPERIOD = 0, set it to 1. + * 04/07/07 1.4 wvd Clean up compiler warnings. + * + ****************************************************************************/ + +#include +#include "calfuse.h" + +int +compute_count_rate(long nevents, float *ptime, long nseconds, + float *ttime, long **data_rate) +{ + float delta_max = 1.0 + FRAME_TOLERANCE; + long j,k; + + *data_rate = (long *) cf_calloc(nseconds, sizeof(long)); + for (j=k=0; j 3200, look for data drop-outs. */ + if (mean_ids_rate > 3200 && nseconds > 4) { + compute_count_rate(nevents, ptime, nseconds, ttime, &data_rate); + flag_array = (int *) cf_calloc(nseconds, sizeof(int)); + + /* If count rate goes to zero, set flag_array. Where possible, + set flags from one second before to two seconds after. */ + for (k=0; k<1; k++) if (data_rate[k] == 0) + flag_array[k] = flag_array[k+1] = flag_array[k+2] = TRUE; + + for ( ; k +#include +#include +#include +#include "calfuse.h" + +#define YLENGTH NYMAX/16 + +int +cf_find_spectra(fitsfile *header, long nevents, + float *weight, float *xfarf, float *yfarf, unsigned char *channel, + unsigned char *timeflags, unsigned char *locflags, int airglow_centroid) +{ + char aper[FLEN_VALUE], instmode[FLEN_VALUE], quality[FLEN_VALUE]; + char key[FLEN_KEYWORD], filename[FLEN_VALUE], detector[FLEN_VALUE]; + double norm, ysum; + float bkgd, peak, ycent, yshift=0; + float yairg[NYMAX], ydist[NYMAX], ysigma[NYMAX]; + float ybin[YLENGTH], sbin[YLENGTH], ycent_tab[8]; + float dy, sigma, xmin, xmax, ycent_air; + int active_ap[2], airglow=FALSE, target_ap, status=0; + int bkgd_num, bkgd_min[8], bkgd_max[8]; + int chan_num, errflg = 0, lwrs; + int chan_order[] = { 3, 2, 1, 7, 6, 5 }; + int center, high, low, npeak, hdu; + int spex_sic, spex_lif, emax, emax_sic, emax_lif, extended; + long i, j, k; + fitsfile *chidfits, *parmfits; + + char CF_PRGM_ID[] = "cf_find_spectra"; + char CF_VER_NUM[] = "1.20"; + + /* Initialize error checking */ + cf_error_init(CF_PRGM_ID, CF_VER_NUM, stderr); + + /* Enter a time stamp into the log */ + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Begin Processing"); + + /* Check whether routine is appropriate for this data file. */ + if ( (errflg = cf_proc_check(header, CF_PRGM_ID)) ) return errflg; + + /* Initialize Y-distribution arrays. */ + for (i = 0; i < NYMAX; i++) + yairg[i] = ydist[i] = ysigma[i] = 0.; + for (i = 0; i < YLENGTH; i++) + ybin[i] = sbin[i] = 0.; + + /* Read header keywords from IDF. */ + FITS_read_key(header, TSTRING, "INSTMODE", instmode, NULL, &status); + FITS_read_key(header, TSTRING, "DETECTOR", detector, NULL, &status); + FITS_read_key(header, TSTRING, "APERTURE", aper, NULL, &status); + extended = cf_source_aper(header, active_ap); + + FITS_read_key(header, TINT, "BKGD_NUM", &bkgd_num, NULL, &status); + for (i = 0; i < bkgd_num; i++) { + sprintf(key, "BKG_MIN%ld", i); + FITS_read_key(header, TINT, key, bkgd_min+i, NULL, &status); + sprintf(key, "BKG_MAX%ld", i); + FITS_read_key(header, TINT, key, bkgd_max+i, NULL, &status); + } + + /* Read expected channel centroids from CHID_CAL file. */ + FITS_read_key(header, TSTRING, "CHID_CAL", filename, NULL, &status); + FITS_open_file(&chidfits, cf_cal_file(filename), READONLY, &status); + for (i = 1; i < 8; i++) { + if (i==4) continue; + if ((i == active_ap[0] || i == active_ap[1]) && !extended) hdu=i+1; + else hdu=i+9; + FITS_movabs_hdu(chidfits, hdu, NULL, &status); + FITS_read_key(chidfits, TFLOAT, "CENTROID", ycent_tab+i, NULL, &status); + } + FITS_read_key(chidfits, TFLOAT, "XMIN", &xmin, NULL, &status); + FITS_read_key(chidfits, TFLOAT, "XMAX", &xmax, NULL, &status); + FITS_close_file(chidfits, &status); + + /* + * Generate photon and airglow arrays as a function of YFARF. + * Ignore events near the detector edge. + */ + xmin += 250; + xmax -= 250; + for (i = 0; i < nevents; i++) { + if (!(timeflags[i] & ~TEMPORAL_DAY) && + (xfarf[i] > xmin) && (xfarf[i] < xmax)) { + if (!locflags[i]) + ydist[cf_nint(yfarf[i])] += weight[i]; + else if (locflags[i] == LOCATION_AIR) + yairg[cf_nint(yfarf[i])] += weight[i]; + } + } + /* Set error array equal to photon counts (= variance). */ + for (i = 0; i < NYMAX; i++) + ysigma[i] = ydist[i]; + + /* If exposure was taken in TTAG mode, estimate BKGD level */ + bkgd = 0.; + if (!strcmp(instmode, "TTAG")) { + k = 0; + for (i = 0; i < bkgd_num; i++) { + for (j = bkgd_min[i]; j <= bkgd_max[i]; j++) { + bkgd += ydist[j]; + k++; + } + } + bkgd /= k; + cf_verbose(3, "Mean background level: %.1f", bkgd); + } + + /* Subtract mean background and bin data by 16 pixels. */ + for (i = 0; i < NYMAX; i++) { + j = i / 16; + ybin[j] += ydist[i] - bkgd; + sbin[j] += ysigma[i]; + } + for (i = 0; i < YLENGTH; i++) sbin[i] = sqrt(sbin[i]); + + /* Read extraction parameters from PARM_CAL file. */ + FITS_read_key(header, TSTRING, "PARM_CAL", filename, NULL, &status); + FITS_open_file(&parmfits, cf_parm_file(filename), READONLY, &status); + FITS_read_key(parmfits,TINT,"SPEX_SIC",&spex_sic,NULL,&status); + FITS_read_key(parmfits,TINT,"SPEX_LIF",&spex_lif,NULL,&status); + FITS_read_key(parmfits,TINT,"EMAX_SIC",&emax_sic,NULL,&status); + FITS_read_key(parmfits,TINT,"EMAX_LIF",&emax_lif,NULL,&status); + FITS_close_file(parmfits,&status); + + /* Determine centroid for each channel. */ + for (k = 0; k < 6; k++) { + chan_num = chan_order[k]; + + /* Is this the LWRS aperture? */ + if (chan_num == 3 || chan_num == 7) + lwrs = TRUE; + else + lwrs = FALSE; + + /* Is it the target aperture? */ + if (chan_num == active_ap[0] || chan_num == active_ap[1]) + target_ap = TRUE; + else + target_ap = FALSE; + + /* If we're in histogram mode, and this is not the target aperture, + move to next aperture. */ + if (!strncmp(instmode, "HIST", 4) && !target_ap) { + if (lwrs) yshift = 0; + continue; + } + + /* First, we compute a centroid from the airglow lines. + For the LWRS aperture, search within 70 pixels of + the expected centroid. Compute the offset between the + measured and tabulated centroids. For the MDRS and HIRS + apertures, apply the offset computed from the LWRS aperture + to the tabulated centroid. + Disregard regions near the bottom and top of the detector. */ + + if (lwrs) { + center = cf_nint(ycent_tab[chan_num]); + dy = 70; + if ((low = center-dy) < 16) low = 16; + if ((high = center+dy) > NYMAX-50) high = NYMAX-50; + norm = ysum = 0.; + for (i = low; i <= high; i++) { + ysum += i * yairg[i]; + norm += yairg[i]; + } + + /* If the airglow lines contain at least 33 events, use their + centroid. If not, use the tabulated centroid. */ + if (norm > 33.) { + ycent = ysum / norm; + yshift = ycent - ycent_tab[chan_num]; + airglow = TRUE; + } + else { + ycent = ycent_tab[chan_num]; + yshift = 0; + airglow = FALSE; + } + } + /* For MDRS and HIRS apertures */ + else + ycent = yshift + ycent_tab[chan_num]; + + /* Remember airglow centroid */ + ycent_air = ycent; + + /* Now we find the centroid for the target spectrum. If we are + in a target aperture and user has specified YCENT, use it. */ + + if (target_ap && ((chan_num<5 && spex_lif>=0 && spex_lif<1024) || + (chan_num>4 && spex_sic>=0 && spex_sic<1024))) { + if (chan_num<5) ycent=spex_lif; + else ycent=spex_sic; + sprintf(key, "YCENT%1d", chan_num); + FITS_update_key(header, TFLOAT, key, &ycent, NULL, &status); + sprintf(quality, "HIGH"); + sprintf(key, "YQUAL%1d", chan_num); + FITS_update_key(header, TSTRING, key, quality, NULL, &status); + cf_verbose(1, "Channel %d: User-specified Y centroid = %.2f", + chan_num, ycent); + continue; + } + + /* If we must find the target spectrum ourselves, use the binned + data array to improve the S/N. Search within 2 binned pixels + of ycent, however it was computed. */ + + center = cf_nint(ycent / 16.); + dy = 2; + if ((low = center - dy) < 3) low = 3; + if ((high = center + dy) > YLENGTH-4) high = YLENGTH-4; + + npeak = 0; + peak = -1.0E5; + for (i = low; i <= high; i++) { + if (ybin[i] > peak) { + peak = ybin[i]; + npeak = i; + } + } + + /* If peak is significant, compute Y centroid for events falling + within 40 pixels of peak. If this number is within 30 pixels + of airglow centroid, use it. If not, use airglow centroid. + Note that we require a higher significance for the SiC LWRS + channel on side 1, because it sits on an elevated background. */ + + if (!strncmp(detector, "1", 1) && chan_num == 7) sigma = 9.; + else sigma = 5.; + + sprintf(quality, "UNKNOWN"); + + if (peak > sigma * sbin[npeak] && !airglow_centroid) { + center = npeak * 16 + 8; + dy = 40; + if ((low = center - dy) < 32) low = 32; + if ((high = center + dy) > NYMAX-50) high = NYMAX-50; + norm = ysum = 0.; + for (i = low; i <= high; i++) { + ysum += i * ydist[i]; + norm += ydist[i]; + } + ycent = ysum / norm; + + /* Don't test offset for HIST data. (wvd, 03/14/2008) */ + if (fabs(ycent - ycent_air) < 30 || !strncmp(instmode, "HIST", 4)) { + sprintf(quality, "HIGH"); + cf_verbose(3, "Channel %d: default centroid: %.2f", + chan_num, ycent_tab[chan_num]); + if (airglow) cf_verbose(3, "Channel %d: airglow centroid: %.2f", + chan_num, ycent_air); + cf_verbose(3,"Channel %d: counts in peak = %.0f, limit = %.0f", + chan_num, peak, sigma * sbin[npeak]); + cf_verbose(2, "Channel %d: using target centroid = %.2lf", + chan_num, ycent); + } + } + /* If peak is not significant or ycent differs too much from + the airglow centroid, use the airglow centroid. */ + if (!strncmp(quality, "UNKNOWN", 1)) { + if (airglow) { + sprintf(quality, "MEDIUM"); + cf_verbose(3, "Channel %d: default centroid: %.2f", + chan_num, ycent_tab[chan_num]); + cf_verbose(3,"Channel %d: peak = %.0f, limit = %.0f", + chan_num, peak, sigma * sbin[npeak]); + cf_verbose(2, "Channel %d: using airglow centroid = %.2lf", + chan_num, ycent); + } + else { + sprintf(quality, "LOW"); + cf_verbose(3,"Channel %d: peak = %f, limit = %f", + chan_num, peak, sigma * sbin[npeak]); + cf_verbose(2, "Channel %d: using default centroid = %.2lf", + chan_num, ycent); + } + } + + /* If centroid lies too far from the default value, use default. */ + if (chan_num<5) emax=emax_lif; else emax=emax_sic; + /* Don't test offset for HIST data. (wvd, 11/25/2008) */ + if (fabs(ycent - ycent_tab[chan_num]) > emax && !strncmp(instmode, "TTAG", 4)) { + if (target_ap) { + cf_verbose(1, "Computed centroid (%.1lf) is too far from " + "expected value.", ycent); + cf_verbose(1, "Channel %d: using default centroid of %.1f", + chan_num, ycent_tab[chan_num]); + } + else { + cf_verbose(2, "Channel %d: using default centroid of %.1f", + chan_num, ycent_tab[chan_num]); + } + ycent = ycent_tab[chan_num]; + sprintf(quality, "LOW"); + } + + /* Write results to file header */ + sprintf(key, "YCENT%1d", chan_num); + FITS_update_key(header, TFLOAT, key, &ycent, NULL, &status); + sprintf(key, "YQUAL%1d", chan_num); + FITS_update_key(header, TSTRING, key, quality, NULL, &status); + } + + cf_proc_update(header, CF_PRGM_ID, "COMPLETE"); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Done Processing"); + + return status; +} diff --git a/src/libcf/cf_fpa_position.c b/src/libcf/cf_fpa_position.c new file mode 100644 index 0000000..fd7229c --- /dev/null +++ b/src/libcf/cf_fpa_position.c @@ -0,0 +1,231 @@ +/**************************************************************************** + * + * Synopsis: cf_fpa_position(fitsfile *header, long nevents, float *x, + * unsigned char *channel) + * + * Description: Modify X position of photon events to account for an offset + * of the focal plane assembly (FPA) + * + * Arguments: fitsfile *header Pointer to the FITS header + * of the Intermediate Data File + * long npts Number of photons in the file + * float *x X positions for each photon event + * unsigned char *channel Assigned channel of each photon + * + * Calls: None + * + * Return: 0 on success + * + * History: 09/04/02 v1.1 wvd Based on cf_dpix by HSU + * 01/14/03 v1.3 wvd Rename cf_fpa_pos to cf_read_fpa_pos + * Move spectrograph optical parameters + * to separate calibration file. + * Abandon linear wavelength scale. + * 02/13/03 v1.4 wvd Write FPA shifts to file header. + * 04/07/03 v1.5 wvd Change keywords to FPADXLIF and + * FPADXSIC. Implement cf_verbose. + * Comment out cf_proc_check. + * Test channel[i] as int, not char. + * 05/20/03 v1.6 rdr Added call to cf_proc_check. + * 08/21/03 v1.7 wvd Change channel to unsigned char. + * 08/23/05 v1.8 wvd If either FPA position is out of + * bounds, issue a warning and set + * that FPA correction to zero. + * 08/01/05 v1.9 wvd Broaden FPA limits by +/- 1. + * 09/06/05 v1.10 wvd Correct for both X and Z motions + * of FPA. + * Delete call to cf_read_fpa_pos.c + * 12/02/05 v1.11 wvd Delete unused variables. + * 04/07/07 v1.12 wvd Clean up compiler warnings. + * + ****************************************************************************/ + +#include +#include +#include +#include "calfuse.h" + +#define PIX1 2500 /* PIX1,2 are just inside the non-linear */ +#define PIX2 13500 /* regions of the detector */ + +int cf_fpa_position(fitsfile *header, long nevents, float *x, + unsigned char *channel) +{ + char CF_PRGM_ID[] = "cf_fpa_position"; + char CF_VER_NUM[] = "1.12"; + + int errflg=0, status=0, hdutype, hdunum; + int nwave; /* number of pixels in calibration file */ + char aperture[FLEN_VALUE]; /* aperture keyword from FITS header */ + char detector[FLEN_VALUE]; /* detector keyword from FITS header */ + char wave_file[FLEN_FILENAME]; /* name of wavelength calibration file */ + char spec_file[FLEN_FILENAME]; /* name of spectrograph calibration file */ + long i; + /* Spectrograph optical parameters */ + float alpha, alpha_lif, alpha_sic, sigma_lif, sigma_sic, diam; + float *wavelength; /* wavelengths read from calibration file */ + float fpaxlifdata; /* LiF FPA X position in microns for spectrum */ + float fpaxsicdata; /* SiC FPA X position in microns for spectrum */ + float fpaxcal; /* FPA X position in microns for calibration file */ + float dxfpa; /* fpax_data - fpaxcal */ + float fpazlifdata; /* LiF FPA Z position in microns for spectrum */ + float fpazsicdata; /* SiC FPA Z position in microns for spectrum */ + float fpazcal; /* FPA Z position in microns for calibration file */ + float dzfpa; /* fpaz_data - fpazcal */ + float dpix, dpix_LiF, dpix_SiC; /* Spectral shift (in pixels)*/ + + double w1, w2; /* wavelengths at which to sample calibration */ + double beta1,beta2; /* grating exit angle for w1, w2 */ + double sinalpha; /* sin (spectrograph entrance angle) */ + double cosalpha; /* cos (spectrograph entrance angle) */ + double sigma; /* grating groove spacing in Angstroms */ + double cosbeta; /* cos (mean grating exit angle) */ + double pixscale; /* mean effective microns/pixel for det segment */ + fitsfile *specfits, *wavefits; + + /* Initialize error checking */ + cf_error_init(CF_PRGM_ID, CF_VER_NUM, stderr); + + /* Enter a timestamp into the log. */ + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Begin Processing"); + + /* Check whether routine is appropriate for this data file. */ + if ((errflg = cf_proc_check(header, CF_PRGM_ID))) return errflg; + + /* Read keywords from data file header. */ + FITS_read_key(header, TSTRING, "DETECTOR", detector, NULL, &status); + FITS_read_key(header, TSTRING, "APERTURE", aperture, NULL, &status); + FITS_read_key(header, TFLOAT, "FPASXPOS", &fpaxsicdata, NULL, &status); + FITS_read_key(header, TFLOAT, "FPALXPOS", &fpaxlifdata, NULL, &status); + FITS_read_key(header, TFLOAT, "FPASZPOS", &fpazsicdata, NULL, &status); + FITS_read_key(header, TFLOAT, "FPALZPOS", &fpazlifdata, NULL, &status); + FITS_read_key(header, TSTRING, "SPEC_CAL", spec_file, NULL, &status); + FITS_read_key(header, TSTRING, "WAVE_CAL", wave_file, NULL, &status); + + /* Read spectrograph optical parameters from SPEC_CAL file. */ + FITS_open_file(&specfits, cf_cal_file(spec_file), READONLY, &status); + FITS_read_key(specfits, TFLOAT, "ALPHALIF", &alpha_lif, NULL, &status); + FITS_read_key(specfits, TFLOAT, "ALPHASIC", &alpha_sic, NULL, &status); + FITS_read_key(specfits, TFLOAT, "SIGMALIF", &sigma_lif, NULL, &status); + FITS_read_key(specfits, TFLOAT, "SIGMASIC", &sigma_sic, NULL, &status); + FITS_read_key(specfits, TFLOAT, "DIAM", &diam, NULL, &status); + FITS_close_file(specfits, &status); + + /* Determine the extension number (LiF) from aperture */ + hdunum = 4; /* Default is LWRS */ + if (!strcmp(aperture, "HIRS")) hdunum = 2; + if (!strcmp(aperture, "MDRS")) hdunum = 3; + + /* Open wavelength calibration file */ + FITS_open_file(&wavefits, cf_cal_file(wave_file), READONLY, &status); + + /* Loop over the two apertures; first (i==0) LiF, then SiC. */ + /* Determine shifts for LiF and SiC channels. */ + for(i=0; i<2; i++) { + + /* Move to appropriate HDU in WAVECAL file. */ + hdunum += i*4; + FITS_movabs_hdu(wavefits, hdunum, &hdutype, &status); + + /* Get FPA position for which WAVECAL was derived */ + FITS_read_key(wavefits, TFLOAT, "FPACXPOS", &fpaxcal, NULL, &status); + FITS_read_key(wavefits, TFLOAT, "FPACZPOS", &fpazcal, NULL, &status); + + /* Read the wavelength array from the WAVECAL file. */ + nwave=cf_read_col(wavefits, TFLOAT,"WAVELENGTH", (void **) &wavelength); + + /* Set LiF/SIC-dependent quantities */ + if (i == 1) { /* SiC data */ + dxfpa = fpaxsicdata - fpaxcal; + dzfpa = fpazsicdata - fpazcal; + sigma = sigma_sic; + alpha = alpha_sic; + } else { /* LiF data */ + dxfpa = fpaxlifdata - fpaxcal; + dzfpa = fpazlifdata - fpazcal; + sigma = sigma_lif; + alpha = alpha_lif; + } + /* + * Compute mean pixel scale from points just inside the + * highly-nonlinear regions at edges of detectors */ + w1 = wavelength[PIX1]; + w2 = wavelength[PIX2]; + sinalpha = sin (alpha * RADIAN); + cosalpha = cos (alpha * RADIAN); + beta1 = asin (w1/sigma - sinalpha); + beta2 = asin (w2/sigma - sinalpha); + cosbeta = cos ((beta1 + beta2)/2.); /* mean cosbeta for segment */ + pixscale = diam * fabs(beta1 - beta2) * 1000. / (double)(PIX2-PIX1); + + /* Compute shift of spectrum in pixels due to the FPA offset. */ + if (i == 1) /* SiC data */ + dpix = (dxfpa * cosalpha + dzfpa * sinalpha) / cosbeta / pixscale; + + else /* LiF data */ + dpix = (dxfpa * cosalpha - dzfpa * sinalpha) / cosbeta / pixscale; + + /* For side 2, multiply the above expressions by -1. */ + if (!strncmp(detector, "2", 1)) + dpix *= -1; + + /* Write info to log file */ + if (i == 1) { + dpix_SiC = dpix; + cf_verbose(3, "FPAX data: %8.3f FPAX calib: %8.3f", + fpaxsicdata, fpaxcal); + cf_verbose(3, "FPAZ data: %8.3f FPAZ calib: %8.3f", + fpazsicdata, fpazcal); + cf_verbose(2, "SiC spectra to be shifted by %8.3f pixels", dpix_SiC); + } + else { + dpix_LiF = dpix; + cf_verbose(3, "FPAX data: %8.3f FPAX calib: %8.3f", + fpaxlifdata, fpaxcal); + cf_verbose(3, "FPAZ data: %8.3f FPAZ calib: %8.3f", + fpazlifdata, fpazcal); + cf_verbose(2, "LiF spectra to be shifted by %8.3f pixels", dpix_LiF); + } + + } /* End of i loop */ + + /* Close the WAVECAL file */ + FITS_close_file(wavefits, &status); + + /* If tabulated FPA position is out of range, set the corresponding + dpix value to zero and issue a warning. */ + if (fpaxlifdata < -1 || fpaxlifdata > 401) { + dpix_LiF = 0; + cf_if_warning("Keyword FPALXPOS is out of bounds. Setting FPADXLIF = 0."); + } + if (fpaxsicdata < -1 || fpaxsicdata > 401) { + dpix_SiC = 0; + cf_if_warning("Keyword FPASXPOS is out of bounds. Setting FPADXSIC = 0."); + } + + /* Shift only photons with assigned apertures. */ + for(i = 0; i < nevents; i++) { + switch(channel[i]) { + case 1: case 2: case 3: case 4: + x[i] += dpix_LiF; + break; + case 5: case 6: case 7: case 8: + x[i] += dpix_SiC; + break; + default: + break; + } + } + + /* Write shifts to IDF file header */ + FITS_update_key(header, TFLOAT, "FPADXLIF", &dpix_LiF, NULL, &status); + FITS_update_key(header, TFLOAT, "FPADXSIC", &dpix_SiC, NULL, &status); + + /* Update processing flags. */ + cf_proc_update(header, CF_PRGM_ID, "COMPLETE"); + + /* Enter a timestamp into the log. */ + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Done processing"); + + return status; +} diff --git a/src/libcf/cf_fuv_init.c b/src/libcf/cf_fuv_init.c new file mode 100644 index 0000000..a2bb181 --- /dev/null +++ b/src/libcf/cf_fuv_init.c @@ -0,0 +1,592 @@ +/***************************************************************************** + * 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; +} diff --git a/src/libcf/cf_geometric_distort.c b/src/libcf/cf_geometric_distort.c new file mode 100644 index 0000000..1164b5c --- /dev/null +++ b/src/libcf/cf_geometric_distort.c @@ -0,0 +1,145 @@ +/**************************************************************************** + * + * Synopsis: cf_geometric_distort(fitsfile *header, long nevents, + * float *xfarf, float *yfarf, + * unsigned char *locflags) + * + * Description: Corrects the X and Y positions of the event for geometric + * distortion. + * + * Arguments: fitsfile *header Pointer to the location of the FITS + * header of the Intermediate Data File + * long nevents number of photons in the file + * float *xfarf X positions for each photon event + * float *yfarf Y positions for each photon event + * unsigned char *locflags Location flags for each event + * + * Calls : None + * + * Return: 0 on success + * + * History: 08/09/02 1.1 rdr Begin work + * 11/12/02 1.2 peb Added check to move only events in + * active region. Added locflags to + * function cal. + * 03/11/03 1.3 wvd Changed locflags to unsigned char. + * 05/20/03 1.4 rdr Added call to cf_proc_check + * 07/29/03 1.5 wvd If cf_proc_check fails, return errflg. + * 03/26/04 1.6 rdr Modify specbiny + * 04/05/04 1.7 wvd Modify specbiny only if specbiny > 1. + * 04/07/07 1.8 wvd Clean up compiler warnings. + * + ****************************************************************************/ + +#include +#include +#include "calfuse.h" + +int +cf_geometric_distort(fitsfile *header, long nevents, float *xfarf, + float *yfarf, unsigned char *locflags) +{ + char CF_PRGM_ID[] = "cf_geometric_distort"; + char CF_VER_NUM[] = "1.8"; + + char geomfile[FLEN_VALUE]={'\0'}; + short *geomx_img, *geomy_img; + int errflg=0, status=0, hdutype, anynull, nullval; + int specbiny ; + long fpixel=1, j; + long xdim_gx, ydim_gx, xdim_gy, ydim_gy, npix_gx, npix_gy; + float scale_gx=1., zero_gx=0., scale_gy=1., zero_gy=0.; + float yexp ; + fitsfile *geomfits=NULL; + + cf_error_init(CF_PRGM_ID, CF_VER_NUM, stderr); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Begin Processing"); + + if ((errflg = cf_proc_check(header, CF_PRGM_ID))) return errflg; + + /* + * Get the name of the calibration file and open it + */ + FITS_read_key(header, TINT, "SPECBINY", &specbiny, NULL, &status); + cf_verbose(5,"Initial value of specbiny=%d",specbiny) ; + FITS_read_key(header, TSTRING, "GEOM_CAL", geomfile, NULL, &status); + cf_verbose(4, "Geometric correction file = %s", geomfile); + FITS_open_file(&geomfits, cf_cal_file(geomfile), READONLY, &status); + + /* Read the y expansion factor from the calibration header */ + FITS_movabs_hdu(geomfits, 1, &hdutype, &status); + FITS_read_key(geomfits, TFLOAT, "YEXPAND", &yexp, NULL, &status); + cf_verbose(3,"Y scale expansion factor = %f",yexp) ; + + /* If SPECBINY > 1, scale by Y expansion factor */ + if (specbiny > 1) { + specbiny = (int) (0.5 + (float) specbiny * yexp) ; + FITS_update_key(header, TINT, "SPECBINY", &specbiny, NULL, &status) ; + cf_verbose(5,"Corrected value of specbiny = %d",specbiny) ; + } + + /* + * Read in the X distortion calibration image + */ + FITS_movabs_hdu(geomfits, 2, &hdutype, &status); + FITS_read_key(geomfits, TLONG, "NAXIS1", &xdim_gx, NULL, &status); + FITS_read_key(geomfits, TLONG, "NAXIS2", &ydim_gx, NULL, &status); + npix_gx = xdim_gx * ydim_gx; + + FITS_read_key(geomfits, TFLOAT, "BSCALE", &scale_gx, NULL, &status); + FITS_read_key(geomfits, TFLOAT, "BZERO", &zero_gx, NULL, &status); + geomx_img = (short *) cf_malloc(sizeof(short) * npix_gx); + fits_set_bscale(geomfits, 1., 0., &status); + FITS_read_img(geomfits, TSHORT, fpixel, npix_gx, &nullval, geomx_img, + &anynull, &status); + /* + * Read the Y distortion calibration image + */ + FITS_movabs_hdu(geomfits, 3, &hdutype, &status); + FITS_read_key(geomfits, TLONG, "NAXIS1", &xdim_gy, NULL, &status); + FITS_read_key(geomfits, TLONG, "NAXIS2", &ydim_gy, NULL, &status); + npix_gy = xdim_gy * ydim_gy; + + FITS_read_key(geomfits, TFLOAT, "BSCALE", &scale_gy, NULL, &status); + FITS_read_key(geomfits, TFLOAT, "BZERO", &zero_gy, NULL, &status); + geomy_img = (short *) cf_malloc(sizeof(short) * npix_gy); + fits_set_bscale(geomfits, 1., 0., &status); + FITS_read_img(geomfits, TSHORT, fpixel, npix_gy, &nullval, geomy_img, + &anynull, &status); + FITS_close_file(geomfits, &status); + /* + * Make sure that the X and Y distortion images are the same size + */ + if (xdim_gx != xdim_gy || ydim_gx != ydim_gy) + cf_if_warning("X and Y distortion images not the same size."); + /* + * Use the data in the geometric distortion calibration images to + * correct XFARF and YFARF + */ + for (j=0; j ydim_gy-1) + yndx = ydim_gy-1; + + ndx = yndx*xdim_gx + xndx; + xfarf[j] += geomx_img[ndx]*scale_gx + zero_gx; + yfarf[j] += geomy_img[ndx]*scale_gy + zero_gy; + } + } + free(geomx_img); + free(geomy_img); + + cf_proc_update(header, CF_PRGM_ID, "COMPLETE"); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Done Processing"); + + return 0; +} diff --git a/src/libcf/cf_grating_motion.c b/src/libcf/cf_grating_motion.c new file mode 100644 index 0000000..fe50d63 --- /dev/null +++ b/src/libcf/cf_grating_motion.c @@ -0,0 +1,432 @@ +/**************************************************************************** + * Johns Hopkins University + * Center For Astrophysical Sciences + * FUSE + ***************************************************************************** + * + * Synopsis: cf_grating_motion(header, nevents, time, x, y, channel, + * ntimes, ttime, tsunrise) + * + * Description: Reads spectral shift caused by thermal grating motions + * and corrects the X and Y locations of each photon event. + * + * fitsfile *header Pointer to the FITS header of the + * Intermediate Data File + * long nevents Number of photons in the file + * int *time Time (in seconds) since exposure start + * float *x Position of the photon (in pixels) + * float *y Position of the photon (in pixels) + * unsigned char channel Channel ID of each photon + * long ntimes Number of entries in timeline table + * float ttime Time array of timeline table + * short tsunrise Time since last sunrise + * + * Returns: 0 on success + * + * History: 09/05/02 1.0 RDR Begin work; adapted from cf_make_shift + * 04/21/03 1.3 wvd Use tsunrise array from timeline table. + * Do not assume that ttime is continuous. + * 05/20/03 1.4 rdr Added call to cf_proc_check + * 08/21/03 1.5 wvd Change channel to unsigned char. + * 06/25/04 1.6 wvd Estimate time between sunrises using + * orbit period in file header. + * 03/22/05 1.7 wvd Change tsunrise from float to short. + * Read orbital period from file header. + * 04/15/05 1.8 wvd Close GRAT_CAL file before exiting. + * If ORBPERID keyword is not found, + * assume that orbit period is 6000 s. + * 12/30/05 1.9 wvd Current algorithm corrects for orbital + * drift of spectrum, but wavelength zero + * point still varies with beta angle and + * observation date. New subroutine + * corrects LiF 1 data for these effects. + * 07/06/06 2.0 wvd Rewrite to use Dave Sahnow's new + * grating-correction file (version 003). + * 07/12/06 2.1 wvd Modify to read an arbitrary number of + * extensions, each with phase information + * in file header keywords. + * 10/20/06 2.2 wvd Grating motion also depends on APER_PA. + * Now we read it from the file header + * and select appropriate coefficients. + * If no correction is defined for a + * particular set of parameters, set + * 11/28/06 2.3 wvd Grating motion includes a long-term, + * non-periodic drift. Read it from the + * first four extensions of GRAT_CAL file. + * 04/07/07 2.4 wvd Clean up compiler warnings. + * + ****************************************************************************/ + +#include +#include +#include +#include +#include "calfuse.h" + +static int +read_nonperiodic_shifts(fitsfile *header, fitsfile *shiftfits, + long ntimes, float *dxlif, float *dylif, float *dxsic, float *dysic) +{ + char channel[FLEN_VALUE], comment[FLEN_CARD], detector[FLEN_VALUE]; + int nrows, tndx; + int status=0, hdutype=0, hdunum=0; + long i; + float *mjd, *xshift, *yshift; + double expstart; + + /* Read header keywords from data file. */ + fits_read_key(header, TDOUBLE, "EXPSTART", &expstart, NULL, &status); + FITS_read_key(header, TSTRING, "DETECTOR", detector, NULL, &status); + + /* First do the LiF channels */ + if (!strncmp(detector,"1",1)) { + hdunum=2; + } else if (!strncmp(detector,"2",1)) { + hdunum=4; + } else { + cf_if_error("Cannot parse DETECTOR keyword in data file."); + } + cf_verbose(3, "Reading HDU %d of GRAT_CAL file.", hdunum); + + FITS_movabs_hdu(shiftfits, hdunum, &hdutype, &status); + FITS_read_key(shiftfits, TSTRING, "CHANNEL", channel, NULL, &status); + sprintf(comment, "LiF%c", detector[0]); + if (strncmp(channel, comment, 4)) + cf_if_error("Cannot find %s correction info in extension %d", + comment, hdunum); + + /* Read X and Y corrections as a function of time. */ + nrows = cf_read_col(shiftfits, TFLOAT, "MJD", (void *) &mjd); + nrows = cf_read_col(shiftfits, TFLOAT, "XSHIFT", (void *) &xshift); + nrows = cf_read_col(shiftfits, TFLOAT, "YSHIFT", (void *) &yshift); + + /* Select appropriate MJD for this exposure. */ + i = 0; + while (expstart > mjd[i] && i < nrows) i++; + tndx = i-1; + if (tndx < 0) tndx = 0; + cf_verbose(3,"EXPSTART = %g", expstart); + cf_verbose(3,"Using LiF corrections for MJD >= %g", mjd[tndx]); + if (tndx < nrows-1) + cf_verbose(3," and MJD < %g", mjd[tndx+1]); + cf_verbose(3,"xshift = %f, yshift = %f", xshift[tndx], yshift[tndx]); + + /* Copy X and Y corrections to output arrays. */ + for (i = 0; i < ntimes; i++) { + dxlif[i] = xshift[tndx]; + dylif[i] = yshift[tndx]; + } + + /* Now do the SiC channels */ + hdunum += 1; + cf_verbose(3, "Reading HDU %d of GRAT_CAL file.", hdunum); + FITS_movabs_hdu(shiftfits, hdunum, &hdutype, &status); + FITS_read_key(shiftfits, TSTRING, "CHANNEL", channel, NULL, &status); + sprintf(comment, "SiC%c", detector[0]); + if (strncmp(channel, comment, 4)) + cf_if_error("Cannot find %s correction info in extension %d", + comment, hdunum); + + /* Read X and Y corrections as a function of time. */ + nrows = cf_read_col(shiftfits, TFLOAT, "MJD", (void *) &mjd); + nrows = cf_read_col(shiftfits, TFLOAT, "XSHIFT", (void *) &xshift); + nrows = cf_read_col(shiftfits, TFLOAT, "YSHIFT", (void *) &yshift); + + /* Select appropriate MJD for this exposure. */ + i = 0; + while (expstart > mjd[i] && i < nrows) i++; + tndx = i-1; + if (tndx < 0) tndx = 0; + cf_verbose(3,"Using SiC corrections for MJD >= %g", mjd[tndx]); + if (tndx < nrows-1) + cf_verbose(3," and MJD < %g", mjd[tndx+1]); + cf_verbose(3,"xshift = %f, yshift = %f", xshift[tndx], yshift[tndx]); + + /* Copy X and Y corrections to output arrays. */ + for (i = 0; i < ntimes; i++) { + dxsic[i] = xshift[tndx]; + dysic[i] = yshift[tndx]; + } + + return 0; +} + + +static int +read_periodic_shifts(fitsfile *header, fitsfile *shiftfits, int ncorrection, + double *lif_mjd0, double *lif_period, double *sic_mjd0, double *sic_period, + double *lif_x_coef, double *lif_y_coef, double *sic_x_coef, double *sic_y_coef) +{ + char detector[FLEN_CARD], channel[FLEN_CARD], comment[FLEN_CARD]; + int status=0, hdutype=0, hdunum=0, anynul=0; + int i, nregions, region, typecode; + long max_coeff, ncoeff, width; + float aper_pa, *aperpalo, *aperpahi; + float *betalo, *betahi, *polelo, *polehi; + double beta, pole, sunang; + + /* Initialize variables. */ + *lif_mjd0 = *lif_period = *sic_mjd0 = *sic_period = 0.; + for (i = 0; i < 11; i++) { + lif_x_coef[i] = 0.; + lif_y_coef[i] = 0.; + sic_x_coef[i] = 0.; + sic_y_coef[i] = 0.; + } + + FITS_read_key(header, TFLOAT, "APER_PA", &aper_pa, NULL, &status); + FITS_read_key(header, TDOUBLE, "SUNANGLE", &sunang, NULL, &status); + FITS_read_key(header, TDOUBLE, "POLEANGL", &pole, NULL, &status); + FITS_read_key(header, TSTRING, "DETECTOR", detector, NULL, &status); + while (999.9 > aper_pa && aper_pa > 360.) aper_pa -= 360.; + while (aper_pa < 0.) aper_pa += 360.; + beta = 180.0 - sunang; + + cf_verbose(3, "S/C orientation: beta = %5.1f, pole = %5.1f, aper_pa = %5.1f", + beta, pole, aper_pa); + + /* First do the LiF channels */ + if (!strncmp(detector,"1",1)) { + hdunum=2; + } else if (!strncmp(detector,"2",1)) { + hdunum=4; + } else { + cf_if_error("Cannot parse DETECTOR keyword in read_shift_file"); + } + hdunum += ncorrection * 4; + cf_verbose(3, "Reading HDU %d of GRAT_CAL file.", hdunum); + + FITS_movabs_hdu(shiftfits, hdunum, &hdutype, &status); + FITS_read_key(shiftfits, TSTRING, "CHANNEL", channel, NULL, &status); + sprintf(comment, "LiF%c", detector[0]); + if (strncmp(channel, comment, 4)) + cf_if_error("Cannot find %s correction info in extension %d", + comment, hdunum); + + if (ncorrection > 1) { + FITS_read_key(shiftfits, TDOUBLE, "PERIOD", lif_period, NULL, &status); + FITS_read_key(shiftfits, TDOUBLE, "MJD_ZERO", lif_mjd0, NULL, &status); + cf_verbose(3, "%s: period = %g, mjd_zero = %g", + channel, *lif_period, *lif_mjd0); + } + + nregions = cf_read_col(shiftfits, TFLOAT, "BETALO", (void *) &betalo); + nregions = cf_read_col(shiftfits, TFLOAT, "BETAHI", (void *) &betahi); + nregions = cf_read_col(shiftfits, TFLOAT, "POLELO", (void *) &polelo); + nregions = cf_read_col(shiftfits, TFLOAT, "POLEHI", (void *) &polehi); + nregions = cf_read_col(shiftfits, TFLOAT, "APERPALO", (void *) &aperpalo); + nregions = cf_read_col(shiftfits, TFLOAT, "APERPAHI", (void *) &aperpahi); + FITS_get_coltype(shiftfits, 7, &typecode, &ncoeff, &width, &status); + max_coeff = ncoeff; + + for (i = 0; i < nregions; i++) + if (betalo[i] <= beta && beta < betahi[i] && + polelo[i] <= pole && pole < polehi[i] && + aperpalo[i] <= aper_pa && aper_pa < aperpahi[i]) break; + + if (i == nregions) + cf_verbose(3, "LiF correction not defined for beta = %g, pole = %g, " + "aper_pa = %g", beta, pole, aper_pa); + else { + cf_verbose(3, "LIF REGION %2d: beta = %g - %g, pole = %g - %g,", + i, betalo[i], betahi[i], polelo[i], polehi[i]); + cf_verbose(3, " aper_pa = %g - %g, %d coefficients", + aperpalo[i], aperpahi[i], ncoeff); + + region = i+1; /* CFITSIO counts from 1, not 0. */ + FITS_read_col(shiftfits, TDOUBLE, 7, region, 1, ncoeff, NULL, lif_x_coef, + &anynul, &status); + FITS_read_col(shiftfits, TDOUBLE, 8, region, 1, ncoeff, NULL, lif_y_coef, + &anynul, &status); + } + + /* Now the SiC channels */ + hdunum += 1; + cf_verbose(3, "Reading HDU %d of GRAT_CAL file.", hdunum); + FITS_movabs_hdu(shiftfits, hdunum, &hdutype, &status); + FITS_read_key(shiftfits, TSTRING, "CHANNEL", channel, NULL, &status); + sprintf(comment, "SiC%c", detector[0]); + if (strncmp(channel, comment, 4)) + cf_if_error("Cannot find %s correction info in extension %d", + comment, hdunum); + + if (ncorrection > 1) { + FITS_read_key(shiftfits, TDOUBLE, "PERIOD", sic_period, NULL, &status); + FITS_read_key(shiftfits, TDOUBLE, "MJD_ZERO", sic_mjd0, NULL, &status); + cf_verbose(3, "%s: period = %g, mjd_zero = %g", + channel, *sic_period, *sic_mjd0); + } + + nregions = cf_read_col(shiftfits, TFLOAT, "BETALO", (void *) &betalo); + nregions = cf_read_col(shiftfits, TFLOAT, "BETAHI", (void *) &betahi); + nregions = cf_read_col(shiftfits, TFLOAT, "POLELO", (void *) &polelo); + nregions = cf_read_col(shiftfits, TFLOAT, "POLEHI", (void *) &polehi); + nregions = cf_read_col(shiftfits, TFLOAT, "APERPALO", (void *) &aperpalo); + nregions = cf_read_col(shiftfits, TFLOAT, "APERPAHI", (void *) &aperpahi); + FITS_get_coltype(shiftfits, 7, &typecode, &ncoeff, &width, &status); + if (max_coeff < ncoeff) max_coeff = ncoeff; + + for (i = 0; i < nregions; i++) + if (betalo[i] <= beta && beta < betahi[i] && + polelo[i] <= pole && pole < polehi[i] && + aperpalo[i] <= aper_pa && aper_pa < aperpahi[i]) break; + + if (i == nregions) + cf_verbose(3, "SiC correction not defined for beta = %g, pole = %g, " + "aper_pa = %g", beta, pole, aper_pa); + else { + cf_verbose(3, "SIC REGION %2d: beta = %g - %g, pole = %g - %g,", + i, betalo[i], betahi[i], polelo[i], polehi[i]); + cf_verbose(3, " aper_pa = %g - %g, %d coefficients", + aperpalo[i], aperpahi[i], ncoeff); + + region = i+1; /* CFITSIO counts from 1, not 0. */ + FITS_read_col(shiftfits, TDOUBLE, 7, region, 1, ncoeff, NULL, sic_x_coef, + &anynul, &status); + FITS_read_col(shiftfits, TDOUBLE, 8, region, 1, ncoeff, NULL, sic_y_coef, + &anynul, &status); + } + + cf_verbose(2, "Fourier coefficients of grating-motion correction:"); + cf_verbose(2," LiF X LiF Y SiC X SiC Y"); + for (i=0; i 0 && channel[j] < 4) { + x[j] += dxlif[k]; + y[j] += dylif[k]; + } + else if (channel[j] > 4) { + x[j] += dxsic[k]; + y[j] += dysic[k]; + } + } + + /* Release memory. */ + free(dxlif); + free(dylif); + free(dxsic); + free(dysic); + + cf_proc_update(header, CF_PRGM_ID, "COMPLETE"); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Finished execution."); + + return status; +} diff --git a/src/libcf/cf_header_io.c b/src/libcf/cf_header_io.c new file mode 100644 index 0000000..d534ac2 --- /dev/null +++ b/src/libcf/cf_header_io.c @@ -0,0 +1,110 @@ +/***************************************************************************** + * Johns Hopkins University + * Center For Astrophysical Sciences + * FUSE + ***************************************************************************** + * + * Synopsis: cf_copy_to_memory(*infile, **memp); + * + * Description: Returns an in-memory FITS file pointer + * + * + * Arguments: char *infile Input data file name + * fitsfile **memp In memory FITS file pointer + * + * Returns: None + * + * History: 08/15/2002 1.0 jch Initial coding + * 12/18/03 bjg Change calfusettag.h to calfuse.h + * + ****************************************************************************/ + + +#include +#include +#include "calfitsio.h" +#include "calfuse.h" + +void +cf_read_header(char *infile, fitsfile **memp) +{ + fitsfile *ip; /* input file pointer */ + int status=0; /* status used in CFITSIO */ + + /* open the input file */ + FITS_open_file(&ip, infile, READONLY, &status); + + /* create the temp file in memory */ + FITS_create_file(memp, "mem://", &status); + + /* copy the input primary HDU to the temp file */ + FITS_copy_hdu(ip, *memp, 0, &status); + + /* close the input file */ + FITS_close_file(ip, &status); +} + + +/***************************************************************************** + * Johns Hopkins University + * Center For Astrophysical Sciences + * FUSE + ***************************************************************************** + * + * Synopsis: cf_copy_to_file(*memp, *outfile); + * + * Description: Copy the header in the in-memory FITS file to an output FITS + * file's primary HDU. + * + * + * Arguments: fitsfile *memp In memory FITS file pointer + * char *outfile Output data file name + * + * Returns: None + * + * History: 08/15/2002 jch 1.0 Initial coding + * + ****************************************************************************/ + +void +cf_write_header(fitsfile *memp, char *outfile) +{ + fitsfile *op; /* output file pointer */ + int status=0; /* status used in CFITSIO */ + + int ncards_memp, ncards_op, morekeys=0; + char card[FLEN_CARD]; + + /* Open the output FITS file. */ + FITS_open_file(&op, outfile, READWRITE, &status); + + fits_get_hdrspace(memp, &ncards_memp, &morekeys, &status); + fits_get_hdrspace(op, &ncards_op, &morekeys, &status); + + /* overwrite output file's primary HDU card by card */ + if (ncards_op >= ncards_memp) { + int i; + for (i=1; i<=ncards_memp; i++) { + FITS_read_record(memp, i, card, &status); + FITS_modify_record(op, i, card, &status); + } + /* delete from the bottom */ + for (i=ncards_op; i>=ncards_memp+1; i--) { + FITS_delete_record(op, i, &status); + } + } + else { + int i; + for (i=1; i<=ncards_op; i++) { + FITS_read_record(memp, i, card, &status); + FITS_modify_record(op, i, card, &status); + } + for (i=ncards_op+1; i<=ncards_memp; i++) { + FITS_read_record(memp, i, card, &status); + FITS_write_record(op, card, &status); + } + } + + /* close output file. */ + FITS_close_file(op, &status); +} diff --git a/src/libcf/cf_identify_channel.c b/src/libcf/cf_identify_channel.c new file mode 100644 index 0000000..7d6a8e3 --- /dev/null +++ b/src/libcf/cf_identify_channel.c @@ -0,0 +1,201 @@ +/***************************************************************************** + * Johns Hopkins University + * Center For Astrophysical Sciences + * FUSE + ***************************************************************************** + * + * Synopsis: cf_identify_channel(fitsfile *header, long nevents, + * float *xfarf, float *yfarf, unsigned char *chan, + * unsigned char *locflags, int pad, int final_call) + * + * Description: Assigns an aperture to each photon in the IDF. + * + * Change of logic in v1.11: This routine may be called + * multiple times. All photons are examined and assigned to + * a channel unless final_call = TRUE. On the final call, only + * photons with channel > 0 are considered. Because only photons + * assigned to a channel are motion corrected, the spectrum can + * move on top of previously-rejected photons. We don't want + * to include them in the final spectrum, so leave their channel + * values unchanged. + * + * Change of logic in v1.16: We've decided to use extended- + * source apertures for the non-target channels. These + * apertures can overlap, so we assign disputed photons to + * their most likely source. In decreasing order, these are + * the target aperture, the larger non-target aperture, and + * the smaller non-target aperture. + * + * Arguments: fitsfile *header Pointer to the location of the FITS + * header of the Intermediate Data File + * long nevents Number of photons in the file + * float *xfarf X positions for each photon event + * float *yfarf Y positions for each photon event + * unsigned char *chan Pointer to pointer to the array + * containing the channel information + * unsigned char *locflags Location flags for each photon + * int pad Switch saying whether to expand the + * width of the tabulated extraction + * window (yes if > 0). The number refers + * to the amount of padding (e.g. pad=5 + * will add 5 pixels to each side of the + * extraction window. + * int final_call This subroutine may be called + * many times. The last time, set + * final_call = TRUE. + * + * Return: 0 on success + * + * History: 08/09/02 1.0 RDR Begin work + * 09/04/02 1.1 rdr Change program so that it just fills + * the channel array rather than creating + * and filling it. Decreased the size of + * the mask. Use the value of pad to + * specify degree of window padding. + * Check for extended source. + * 12/11/02 1.2 RDR Adjust aperture limits by measured + * y centroid (if available) + * 02/11/03 1.3 rdr changed test for ycent values + * 02/12/03 1.6 wvd Don't crash if YCENT# is undefined + * 03/25/03 1.7 rdr Ignore pinhole aperture + * 03/31/03 1.10 wvd Ignore regions where YMAX = YMIN + 1. + * They are not valid channel regions. + * 04/07/03 1.11 wvd Shift channel boundaries to match FPA + * positions. Implement use of cf_verbose. + * Update CHID_COR if final_call = TRUE. + * 05/20/03 1.12 rdr Added call to cf_proc_check + * 07/23/03 1.14 rdr Correct procedure which reads CHID + * calibration file + * 08/21/03 1.15 wvd Change channel to unsigned char. + * 08/25/03 1.16 wvd Use extended windows for non-target + * apertures. Replace aperture mask + * with a grid of aperture limits. + * Use cf_nint() to round floats. + * 08/25/03 1.17 wvd Change coltype from string to int + * in cf_read_col. + * 09/08/03 1.18 wvd Default value is channel[i] = 0. + * Identify low and high values of x + * by setting y limits to -NYMAX. + * 09/18/03 1.19 wvd Consider only photons falling on the + * active area of the detector. + * 11/12/03 1.20 wvd Don't bother with non-target channels + * in HIST mode. + * 06/14/04 1.21 wvd Don't bother shifting extraction + * windows to correct for FPA position. + * If known, shift is not needed. + * 06/17/04 1.22 wvd Because the extraction windows don't + * quite match the WGTS arrays, we pad + * windows by XPAD pixels in X. + * 07/21/04 1.23 wvd Change i from long to int. + * 03/15/05 1.24 wvd Call cf_extraction_limits to get limits + * of extraction windows, rather than + * reading CHID_CAL file directly. + * Do not pad windows in X. + * 03/16/05 1.25 wvd Pass srctype to cf_extraction_limits. + * + ****************************************************************************/ + +#include +#include "calfuse.h" + +int +cf_identify_channel(fitsfile* header, long npts, float* x, float* y, + unsigned char* channel, unsigned char* locflags, int pad, + int final_call) +{ + char CF_PRGM_ID[] = "cf_identify_channel"; + char CF_VER_NUM[] = "1.25"; + + char instmode[FLEN_VALUE], zero=0; + int errflg=0, extended, n_chan=6, status=0; + int active_ap[2], chan, srctype[8]; + int i; /* Always steps through targ_ap */ + int *targ_ap, + lwrs[]={3,7,2,6,1,5}, /* LWRS, MDRS, HIRS (LiF & SiC) */ + mdrs[]={2,6,3,7,1,5}, /* MDRS, LWRS, HIRS (LiF & SiC) */ + hirs[]={1,5,3,7,2,6}; /* HIRS, LWRS, MDRS (LiF & SiC) */ + long j, /* Always steps through extraction window arrays */ + k; /* Always steps through photon list */ + short xint, yint, xmin, xmax, *ymin[6], *ymax[6]; + + /* Initialize error checking */ + cf_error_init(CF_PRGM_ID, CF_VER_NUM, stderr); + + /* Enter a time stamp into the log */ + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Begin Processing"); + + /* Check whether routine is appropriate for this data file. */ + if ((errflg = cf_proc_check(header, CF_PRGM_ID))) return errflg; + + /* If data were taken in HIST mode, ignore non-target channels. */ + FITS_read_key(header, TSTRING, "INSTMODE", instmode, NULL, &status); + if (!strncmp(instmode, "HIST", 4)) n_chan = 2; + + /* Determine source type and active apertures */ + extended = cf_source_aper(header, active_ap); + + /* Set the order in which we will assign photons to channels. */ + switch (active_ap[0]) { + case 1: targ_ap = hirs; + break; + case 2: targ_ap = mdrs; + break; + default: targ_ap = lwrs; + break; + } + + /* For target apertures, srctype reflects target. + Use extended apertures for the rest. */ + for (i = 0; i < 2; i++) srctype[i] = extended; + for ( ; i < n_chan; i++) srctype[i] = 1; + + /* While we're at it, here's one more bit of i/o. */ + if (pad > 0) + cf_verbose(3, "Padding extraction windows by %d Y pixels", pad); + + /* + * Loop through all channels, read extraction limits, + * and apply any requested padding. + */ + for (i = 0; i < n_chan; i++) { + chan = targ_ap[i]; + + /* Read the extraction limits for this aperture. */ + (void) cf_extraction_limits(header, chan, srctype[i], + (ymin+i), (ymax+i), &xmin, &xmax); + + /* Add any padding requested by the user. */ + if (pad > 0) { + for (j = xmin; j <= xmax; j++) { + ymin[i][j] -= pad; + ymax[i][j] += pad; + } + } + } + + /* Loop through photon list. Assign a channel ID to each. */ + cf_verbose(3, "Entering loop to assign channel ID's."); + for (k = 0; k < npts; k++) { + if (final_call && channel[k] == zero) continue; + channel[k] = zero; + if (!(locflags[k] & LOCATION_SHLD)) { + xint = (short) cf_nint(x[k]); + yint = (short) cf_nint(y[k]); + if (xint < xmin || xint > xmax) continue; + for (i = 0; i < n_chan; i++) { + if (yint >= ymin[i][xint] && yint <= ymax[i][xint]) { + channel[k] = (char) targ_ap[i]; + break; + } + } + } + } + + /* If final_call = TRUE, update IDF header keyword for this subroutine. */ + if (final_call) + cf_proc_update(header, CF_PRGM_ID, "COMPLETE"); + + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Done Processing"); + + return status; +} diff --git a/src/libcf/cf_idf_io.c b/src/libcf/cf_idf_io.c new file mode 100644 index 0000000..8d8d43a --- /dev/null +++ b/src/libcf/cf_idf_io.c @@ -0,0 +1,161 @@ +/***************************************************************************** + * Johns Hopkins University + * Center For Astrophysical Sciences + * FUSE + ***************************************************************************** + * + * Synopsis: npts = cf_read_col(fitsfile, coltype, colname, colval) + * + * Description: Procedure to read the values from a column in a FUSE + * Intermediate Data File (IDF). + * Because floating-point data may be stored as shorts, + * must convert data to type expected by calling routine. + * + * Variables: fitsfile *fileptr Pointer to the input file + * int coltype Data type of the column + * (TBYTE, TDOUBLE, TSHORT, or TFLOAT) + * char *colname Name of the column to re read + * (e.g. TIME or XFARF) + * void **colval Address of the array containing + * the data (must be cast to void) + * + * Return: long npts Number of points in the array + * + * Example: + * fitsfile *infits ; + * long npts ; + * float *xfarf ; + * + * FITS_open_file(&infits, argv[1], READWRITE, &status); + * npts = cf_read_col(infits, TFLOAT, "XFARF", (void **) &xfarf); + * + * History: 08/08/02 rdr Begin work + * 06/11/03 wvd v1.4 Pass coltype from calling routine. + * 08/25/03 wvd v1.5 Change coltype from string to int. + * 08/28/03 wvd v1.6 Use CASEINSEN in calls to + * fits_get_colnum + * 12/18/03 bjg v1.7 Change calfusettag.h to calfuse.h + * 04/28/05 wvd v1.8 Allow arrays to be read as doubles. + * 08/24/07 wvd v1.9 Read nrows as type TLONG. + * + *************************************************************************/ + +#include +#include "calfuse.h" + +long +cf_read_col(fitsfile *infits, int coltype, char *colname, void **colval) +{ + int colnum, tcode, intnull=0, anynull, status=0; + long nrows, width, repeat, nentries; + + /* Get the column number of the column to be extracted. */ + FITS_get_colnum(infits, CASEINSEN, colname, &colnum, &status); + + /* Determine the properties of the column. */ + fits_get_coltype(infits, colnum, &tcode, &repeat, &width, &status); + + /* Read the number of rows in the table. */ + FITS_read_key(infits, TLONG, "NAXIS2", &nrows, NULL, &status); + + /* Calculate the number of entries in the table. */ + nentries = nrows * repeat; + + /* Set tcode and width to values expected by calling routine. */ + if (coltype == TFLOAT) { + tcode = TFLOAT; + width = (long) sizeof (float); + } + if (coltype == TDOUBLE) { + tcode = TDOUBLE; + width = (long) sizeof (double); + } + + /* Allocate space for the file. */ + *colval = (void *) cf_malloc(nentries * width); + + /* Read the data from the file. */ + FITS_read_col(infits, tcode, colnum, 1, 1, nentries, &intnull, *colval, + &anynull, &status); + + return nentries; +} + +/***************************************************************************** + * Johns Hopkins University + * Center For Astrophysical Sciences + * FUSE + ***************************************************************************** + * + * Synopsis: cf_write_col(fitsfile, colname, colval, npts) + * + * Description: Procedure to write an array into a specified column of a + * FUSE Intermediate Data File (IDF). + * Because floating-point data may be stored as shorts, + * data type of array may not match that of output file header. + * + * Variables: fitsfile *fileptr Pointer to the input file + * int coltype Data type of the column + * (TBYTE, TDOUBLE, TSHORT, or TFLOAT) + * char *colname Name of the column to re read + * (e.g. TIME or XFARF) + * void **colval Address of the array containing + * the data (must be cast to void) + * long npts Number of points in the array + * + * Reture: status + * + * Example: + * fitsfile *infits ; + * long npts=100 ; + * float *xfarf ; + * + * FITS_open_file(&infits, argv[1], READWRITE, &status); + * npts = cf_read_col(infits, TFLOAT, "XFARF", (void **) &xfarf); + * + * History: 08/08/02 rdr Begin work + * 06/11/03 wvd v1.4 Pass coltype from calling routine. + * Check for overflow in X arrays. + * 08/25/03 wvd v1.5 Change coltype from string to int. + * 08/28/03 wvd v1.6 Use CASEINSEN in calls to + * fits_get_colnum + * + *************************************************************************/ + +int +cf_write_col(fitsfile *infits, int coltype, char *colname, void *colval, + long npts) +{ + int colnum, tcode, status=0; + long i, width, nevents; + + /* Get the column number of the column to be written. */ + FITS_get_colnum(infits, CASEINSEN, colname, &colnum, &status); + + /* Determine the properties of the column. */ + fits_get_coltype(infits, colnum, &tcode, &nevents, &width, &status); + + /* + * If the calling routine and the IDF differ on the data type of this + * array, use the data type from the calling routine. + */ + if (coltype == TFLOAT) { + tcode = TFLOAT; + width = (long) sizeof (float); + } + + /* Check for overflow in X arrays. */ + if (!strncmp(colname, "X", 1)) { + float *x; + x = (float *) colval; + for (i = 0; i < nevents; i++) { + if (x[i] < 0) x[i] = 0.; + if (x[i] > NXMAX - 1) x[i] = NXMAX - 1; + } + } + + /* Write the data to the relevant column. */ + FITS_write_col(infits, tcode, colnum, 1, 1, npts, colval, &status); + + return status; +} diff --git a/src/libcf/cf_ids_dead_time.c b/src/libcf/cf_ids_dead_time.c new file mode 100644 index 0000000..656222e --- /dev/null +++ b/src/libcf/cf_ids_dead_time.c @@ -0,0 +1,109 @@ +/***************************************************************************** + * Johns Hopkins University + * Center For Astrophysical Sciences + * FUSE + ***************************************************************************** + * + * Synopsis: cf_ids_dead_time(fitsfile *header, long nseconds, + * float *aic_rate, float *ids_dtc) + * + * Description: Computes the weighting factor needed to correct + * for the IDS dead time. + * + * Arguments: fitsfile *header Pointer to FITS file containing the + * header of the intermediate data file + * long nseconds The number of timeline values + * float *aic_rate An array of Active Image Counter + * values + * float *ids_dtc Dead-time correction array (returned) + * + * Calls: + * + * Return: 0 on success + * + * History: 10/27/02 1.1 peb Begin work + * 11/11/02 1.2 peb Correct function description and add + * cf_timestamp after IDS__COR check. + * 12/09/02 1.4 wvd Calculate DT correction for each time + * step, then apply to photons. + * Set keyword IDS_DEAD. + * 05/20/03 1.5 rdr Add proc_check call. + * 08/01/03 1.8 wvd Just calculate correction; don't + * apply it. Return ids_dtc array. + * 08/04/03 1.9 wvd Convert aic_rate to type short. + * 11/26/03 1.10 wvd Convert aic_rate to type float. + * 02/09/04 1.11 wvd max_ids_rate depends on instrument + * mode. For TTAG data, include time + * stamps in aic_rate. + * 04/07/07 1.12 wvd Clean up compiler warnings. + * + ****************************************************************************/ + +#include +#include "calfuse.h" + +int +cf_ids_dead_time(fitsfile *header, long nseconds, float *aic_rate, + float *ids_dtc) +{ + char CF_PRGM_ID[] = "cf_ids_dead_time"; + char CF_VER_NUM[] = "1.12"; + + char elecfile[FLEN_VALUE], instmode[FLEN_VALUE]; + int errflg=0, status=0; + long k; + float ids_rate, tstamps, ttperiod; + float mean_ids_dtc = 0.; + float max_ids_rate = 1.; + fitsfile *elecfits; + + cf_error_init(CF_PRGM_ID, CF_VER_NUM, stderr); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Begin Processing"); + if ((errflg = cf_proc_check(header, CF_PRGM_ID))) return errflg; + /* + * Read observing mode and interval between time stamps. + */ + FITS_read_key(header, TSTRING, "INSTMODE", instmode, NULL, &status); + FITS_read_key(header, TFLOAT, "TTPERIOD", &ttperiod, NULL, &status); + /* + * Compute number of time stamps per second (0 for HIST data). + */ + if (!strncmp(instmode, "TTAG", 4)) /* TTAG MODE */ + if (ttperiod > 1e-8) tstamps = 1./ttperiod; + else tstamps = 1.; + else /* HIST MODE */ + tstamps = 0.; + /* + * Maximum IDS rate depends on instrument mode. + */ + FITS_read_key(header, TSTRING, "ELEC_CAL", elecfile, NULL, &status); + FITS_open_file(&elecfits, cf_cal_file(elecfile), READONLY, &status); + if (!strncmp(instmode, "TTAG", 4)) + FITS_read_key(elecfits, TFLOAT, "TTAG_BUS", &max_ids_rate, NULL, &status); + else + FITS_read_key(elecfits, TFLOAT, "HIST_BUS", &max_ids_rate, NULL, &status); + FITS_close_file(elecfits, &status); + cf_verbose(4, "max_ids_rate = %f", max_ids_rate); + /* + * Calculate the IDS dead-time correction. + */ + for (k=0; k max_ids_rate) + ids_dtc[k] = ids_rate/max_ids_rate; + else + ids_dtc[k] = 1.0; + mean_ids_dtc += ids_dtc[k]; + } + /* + * Write mean IDS dead-time correction to file header. + */ + mean_ids_dtc /= nseconds; + cf_verbose(2, "Mean IDS dead-time correction: %f", mean_ids_dtc); + FITS_update_key(header, TFLOAT, "IDS_DEAD", &mean_ids_dtc, NULL, &status); + + cf_proc_update(header, CF_PRGM_ID, "COMPLETE"); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Done processing"); + return 0; +} diff --git a/src/libcf/cf_init_support.c b/src/libcf/cf_init_support.c new file mode 100644 index 0000000..68db0f6 --- /dev/null +++ b/src/libcf/cf_init_support.c @@ -0,0 +1,1344 @@ +/***************************************************************************** + * Johns Hopkins University + * Center For Astrophysical Sciences + * FUSE + ***************************************************************************** + * + * Description: Routines used by cf_ttag_init and cf_hist_init. + * + * History: 07/15/03 v1.1 wvd Move routines from cf_ttag_init + * 07/24/03 1.2 wvd If tsunrise and tsunset get huge, + * store them as floats, not integers. + * 07/30/03 1.5 wvd Omit TZERO and TSCALE for these + * timeline table entries: + * HIGH_VOLTAGE + * LIF_CNT_RATE + * SIC_CNT_RATE + * FEC_CNT_RATE + * AIC_CNT_RATE + * BKGD_CNT_RATE + * This will effectively convert them + * to arrays of shorts. + * Add 0.5 to all count rates in + * anticipation of truncation. + * 08/22/03 1.7 wvd Populate MIN_LIMB keyword. + * 09/03/03 1.8 wvd Implement cf_verbose throughout. + * Add EXP_JITR and EXPNIGHT to IDF header. + * 09/22/03 1.9 wvd Correct comment field for YCENT1 + * 10/02/03 1.10 wvd Modify timeline table: + * - no time gaps + * - set TEMPORAL_OPUS for times outside + * of OPUS good-time intervals. + * Delete cf_get_times. + * Use cf_read_col in cf_get_gti + * and cf_get_geocorona. + * Don't modify gtis[0] for HIST data. + * 10/13/03 1.11 wvd Add 1s to end of timeline table for + * TTAG data. + * 10/15/03 1.12 wvd Swap voltages for detectors 2A and 2B + * if housekeeping file was written + * before April of 2003. + * 10/22/03 1.13 wvd Compute EXPNIGHT for raw data file + * and write to output file header. + * Add YQUALLIF & YQUALSIC keywords. + * 11/25/03 1.14 wvd Raise upper limits on LIF_CNT_RATE and + * SIC_CNT_RATE to 32000. Raise limits + * on FEC_CNT_RATE and AIC_CNT_RATE + * to 64000. Use TZERO = 32768 for + * FEC_CNT_RATE and AIC_CNT_RATE. + * They must be read as floats. + * 01/15/04 1.15 bjg Now performs cnt0 -= 16777216 when + * cnt0 < cnt before computing + * cnt_rate for the first cnt and + * cnt0 in function + * fill_cntrate_array + * cf_timeline 1.6 -> 1.7 + * free the arrays only at the end + * version 1.6 tries to read tflag + * array after it has been freed + * 02/06/04 1.16 wvd Modify fill_cntrate_array() so + * that the output array no longer runs + * 16 seconds behind the HSKP data. + * 02/18/04 1.17 wvd Voltages for detectors 2A and 2B + * are still swapped. Set HKERR_ENDS + * to 20100000. + * 03/04/04 1.18 bjg Read begin and end counters as float + * Set countrate to zero when cntb is more + * than 16777216. + * 03/19/04 bjg FITS data types (TFLOAT, TSTRING, TBYTE) + * now match type of C containers (float, + * char *, char) when reading and writing + * in FITS header. + * 04/06/04 1.19 bjg Include ctype.h + * Functions now return EXIT_SUCCESS + * Remove unused variables + * Remove static keyword in struct key + * definition + * If cnt_rate>32000 set cnt_rate=0 + * 05/07/04 1.20 wvd Delete HKERR_ENDS. If HSKPVERS keyword + * is not present in HSKP file, test to + * determine whether high-voltage arrays + * for 2A and 2B are swapped. + * 05/27/04 1.21 bjg Test counter keywords. If bad, use + * cnt_rate=NEVENTS/exptime or 0 + * 06/14/04 1.22 wvd Add BRIT_OBJ keyword to header. + * Rewrite fill_hv_array() to make it more + * robust. + * If HV values in header are good, use + * them to determine whether HV + * arrays for 2A and 2B are swapped. + * 10/17/04 bjg Replaced lots of + * "while (val +#include +#include +#include +#include +#include +#include "calfuse.h" +#include "sgp4.h" + + +struct key { + char keyword[FLEN_KEYWORD]; + float value; + }; + + +/*********************************************************************** + * + * procedure to get the GTI values from the input file + * + **********************************************************************/ + +int cf_get_gti(fitsfile *infits, double **gtis, double **gtie) { + + char instmode[FLEN_VALUE]; + int ngti, status=0; + float ttperiod; + + cf_verbose(3, "Entering cf_get_gti."); + + /* Read header keywords. */ + FITS_movabs_hdu(infits, 1, NULL, &status); + FITS_read_key(infits, TSTRING, "INSTMODE", instmode, NULL, &status); + FITS_read_key(infits, TFLOAT, "TTPERIOD", &ttperiod, NULL, &status); + if (ttperiod < 1E-6) ttperiod = 1.0; + + /* Move to the second extension and read the GTI's */ + FITS_movabs_hdu(infits, 3, NULL, &status); + ngti = cf_read_col(infits, TDOUBLE, "START", (void **) gtis); + ngti = cf_read_col(infits, TDOUBLE, "STOP", (void **) gtie); + + /* + * If gtis[0] = 0.000, then it is probably wrong. + * Set it equal to the fractional part of gtie[0]. + * In HIST mode, gtis[0] is always 0., so don't change it. + * This trick only works if TTPERIOD = 1.0. + */ + if (**gtis < FRAME_TOLERANCE && !strncmp(instmode, "TTAG", 4) + && fabs(ttperiod - 1.0) < FRAME_TOLERANCE) + **gtis = fmod(*gtie[0], 1.); + + cf_verbose(3, "Exiting cf_get_gti."); + return ngti; +} + +/*********************************************************************** + * + * procedure to get a list of geocoronal line locations from the AIRG + * calibration file + * + ***********************************************************************/ + +int +cf_get_geocorona(fitsfile *outfits, short **gxmin, short **gxmax, + short **gymin, short **gymax) +{ + char airgfile[FLEN_VALUE]; + int nrow, status=0; + fitsfile *airgfits; + + cf_verbose(3, "Entering cf_get_geocorona."); + + /* Read the name of the AIRG calibration file to use and open it */ + FITS_movabs_hdu(outfits, 1, NULL, &status); + FITS_read_key(outfits, TSTRING, "AIRG_CAL", airgfile, NULL, &status); + FITS_open_file(&airgfits, cf_cal_file(airgfile), READONLY, &status); + cf_verbose(3, "AIRG_CAL = %s", airgfile); + + /* + * Move to the first extension and read the positions of the + * geocoronal lines. + */ + FITS_movabs_hdu(airgfits, 2, NULL, &status); + nrow = cf_read_col(airgfits, TSHORT, "XMIN", (void **) gxmin); + nrow = cf_read_col(airgfits, TSHORT, "XMAX", (void **) gxmax); + nrow = cf_read_col(airgfits, TSHORT, "YMIN", (void **) gymin); + nrow = cf_read_col(airgfits, TSHORT, "YMAX", (void **) gymax); + + FITS_close_file(airgfits, &status); + cf_verbose(3, "Exiting cf_get_geocorona."); + return nrow; +} + + +/*********************************************************************** + * + * Procedures to compute times of most recent sunrise and sunset + * + ***********************************************************************/ + +SGP4 set_orbit_parms(fitsfile *); + +static double +sunrise(double mjd_start, SGP4 sgp4) +{ + double ang_sep, mjd, ptime, pos[3], vel[3]; + int i, dn_flag, dn_flag_last; + + dn_flag_last = 1; /* Assume that we begin in night. */ + + for (i=1; i>-8000; i--) { + ptime = (double) i; + mjd = mjd_start + ptime/86400.0; + + /* Get the state vector at time mjd */ + SGP4_getStateVector(sgp4, mjd, pos, vel); + SGP4_precess(pos, mjd, MJD2000); + + dn_flag = eclipse(pos, mjd, &ang_sep); /* 0=day, 1=night */ + + /* We're going backward in time, so sunrise is day into night. */ + if ((dn_flag == 1) && (dn_flag_last == 0)) break; + + dn_flag_last=dn_flag; + } + /* Historically, we've defined sunrise as the time increment after + the change, so add 1 to the number we've just calculated. */ + return (ptime + 1.); +} + + +static double +sunset(double mjd_start, SGP4 sgp4) +{ + double ang_sep, mjd, ptime, pos[3], vel[3]; + int i, dn_flag, dn_flag_last; + + dn_flag_last = 0; /* Assume that we begin in day. */ + + for (i=1; i>-8000; i--) { + ptime = (double) i; + mjd = mjd_start + ptime/86400.0; + + /* Get the state vector at time mjd */ + SGP4_getStateVector(sgp4, mjd, pos, vel); + SGP4_precess(pos, mjd, MJD2000); + + dn_flag = eclipse(pos, mjd, &ang_sep); /* 0=day, 1=night */ + + /* We're going backward in time, so sunset is night into day. */ + if ((dn_flag == 0) && (dn_flag_last == 1)) break; + + dn_flag_last = dn_flag; + } + /* Historically, we've defined sunset as the time increment after + the change, so add 1 to the number we've just calculated. */ + return (ptime + 1.); +} + +/****************************************************************************/ + +static void +fill_cntrate_array(long nsam_hk, long *hk_colval, double *time_hk, + long ntime, double *ttime, float *tarray) +{ + /* + * Procedure to fill an array with count rate housekeeping (HK) + * information, which is tabulated on an approx 16s time interval. + * + * nsam_hk = number of time samples in the housekeeping file + * hk_colval = array containing the housekeeping data + * time_hk = time from the exposure start for each second in the + * houskeeping file + * ntime = number of tabulated rows in the timeline array + * ttime = tabulated times in the timeline array + * tarray = timeline array to be filled, one sample per second + * starting at the start of the exposure + */ + + double hk_time, hk_time0; + long hk_cnt, hk_cnt0; + long i; /* index through timeline table */ + long k; /* index through housekeeping array */ + float cnt_rate = 0.; + + i = k = 0; /* Initialize indices */ + + /* + * Find the first non-negative value in the HK array + */ + while(k < nsam_hk && hk_colval[k] < 0) k++; + hk_cnt0 = hk_colval[k]; + hk_time0 = time_hk[k]; + + /* + * Begin big loop through the timeline table + */ + while (i < ntime) { + + /* Find the next non-negative value in the HK array. */ + k++; + while(k < nsam_hk && hk_colval[k] < 0) k++; + + /* If we've run out of HK entries, + fill in the rest of the timeline and quit. */ + if (k == nsam_hk) { + for ( ; i < ntime; i++) + tarray[i] = cnt_rate; + break; + } + + /* Otherwise, calculate the count rate between + times hk_time0 and hk_time. */ + hk_cnt = hk_colval[k]; + hk_time = time_hk[k]; + if (hk_cnt < hk_cnt0) + hk_cnt0 -= 16777216; + cnt_rate = (hk_cnt - hk_cnt0) / (hk_time - hk_time0); + + /* Populate the timeline table for times less than hk_time */ + while (i < ntime && cf_nlong(ttime[i]) < hk_time) + tarray[i++] = cnt_rate; + + /* Save latest HK time and count values. */ + hk_cnt0 = hk_cnt; + hk_time0 = hk_time; + } +} + + +/****************************************************************************/ + +static void +hv_from_header(fitsfile *outfits, char *det, char *side, long ntime, short *hv) +{ + + char hv_key[FLEN_CARD]; + int det_hv, hv_flag, status=0; + long i; + + fits_read_key(outfits, TINT, "HV_FLAG", &hv_flag, NULL, &status); + if (hv_flag == -1) { + det_hv = -999; + cf_verbose(1, "Bad HV keywords: setting HV to -999 in timeline table."); + } + else { + sprintf(hv_key, "DET%.1sHV%.1sH", det, side); + FITS_read_key(outfits, TINT, hv_key, &det_hv, NULL, &status); + } + if (hv_flag == 0) + cf_verbose(1, "Applying max voltage value to whole exposure."); + + cf_verbose(2, "High voltage = %d", det_hv); + for (i=0; i MAX_EXPTIME) { + TIMES_TOO_BIG = TRUE; + cf_if_warning("Exposure appears to span %0.0f ks. Truncating " + "timeline table.", (gtie[ngti-1] - gtis[0])/1000.); + } + + /* For HIST data, use the good-time intervals + to set the times in the timeline table. */ + if (!strncmp(instmode, "HIST", 4)) { + if (TIMES_TOO_BIG) { + ntime = 0; + for (i = 0; i < ngti; i++) + ntime += (long) (gtie[i] - gtis[i] + 1.5); + ptime = (double *) cf_malloc(sizeof(double) * ntime); + k = 0; + for (i = 0; i < ngti; i++) { + ntime = (long) (gtie[i] - gtis[i] + 1.5); + for (j = 0; j < ntime; j++) + ptime[k++] = gtis[i] + j; + } + ntime = k; + } + else { + ntime = (long) (gtie[ngti-1] - gtis[0] + 1.5); + ptime = (double *) cf_malloc(sizeof(double) * ntime); + for (i = 0; i < ntime; i++) + ptime[i] = gtis[0] + i; + } + } + + /* For TTAG data, use the photon times themselves. */ + else { + FITS_movabs_hdu(outfits, 2, NULL, &status); + nevents = cf_read_col(outfits, TFLOAT, "TIME", (void **) &time); + FITS_movabs_hdu(outfits, 1, NULL, &status); + n_bad_times = 0; + if (TIMES_TOO_BIG) { + last_time = 0; + i = nevents - 1; + while (time[i] > MAX_EXPTIME && i > 0) { + if (fabs(time[i] - last_time) > FRAME_TOLERANCE && n_bad_times < 1024) { + bad_times[n_bad_times++] = time[i]; + last_time = time[i]; + } + i--; + } + last_time = time[i] + 1.; + } + else + last_time = time[nevents-1] + 1.; + first_time = time[0]; + if (first_time < fmod(last_time, 1.)) + first_time = fmod(last_time, 1.) - 1.; + ntime = (long) (last_time - first_time + 1.5) + n_bad_times; + ptime = (double *) cf_malloc(sizeof(double) * ntime); + for (i = 0; i < ntime - n_bad_times; i++) + ptime[i] = first_time + i; + for (j = n_bad_times-1; i < ntime; i++, j--) + ptime[i] = bad_times[j]; + free(time); + } + cf_verbose(2, "Timeline table will contain %ld entries", ntime); + + /* Now generate all of the other arrays in the timeline table. */ + + lon = (double *) cf_calloc(ntime, sizeof(double)); + lat = (double *) cf_calloc(ntime, sizeof(double)); + limbang = (double *) cf_calloc(ntime, sizeof(double)); + vorb = (double *) cf_calloc(ntime, sizeof(double)); + tsunrise = (double *) cf_calloc(ntime, sizeof(double)); + tsunset = (double *) cf_calloc(ntime, sizeof(double)); + hv = (short *) cf_calloc(ntime, sizeof(short)); + lifcr = (float *) cf_calloc(ntime, sizeof(float)); + siccr = (float *) cf_calloc(ntime, sizeof(float)); + feccr = (float *) cf_calloc(ntime, sizeof(float)); + aiccr = (float *) cf_calloc(ntime, sizeof(float)); + bkgdcr = (float *) cf_calloc(ntime, sizeof(float)); + tflag = (unsigned char *) cf_calloc(ntime, sizeof(unsigned char)); + ycentl = (float *)cf_calloc(ntime, sizeof(float)); + ycents = (float *)cf_calloc(ntime, sizeof(float)); + + for (i=0; i limbang[i]) min_limb = limbang[i]; + + dn_flag = eclipse(pos, mjd, &ang_sep); /* 0=day, 1=night */ + + /* The first time through, and after any breaks in the timeline, + * compute times of most recent sunrise and sunset. */ + if ((i == 0) || (ptime[i] - ptime[i-1] - 1. > FRAME_TOLERANCE)) { + lastsunrise = ptime[i] + sunrise(mjd, sgp4); + lastsunset = ptime[i] + sunset(mjd, sgp4); + if (lastsunset > lastsunrise) dn_flag_last = 1 ; + else dn_flag_last = 0 ; + /* The first time through, compute the orbital period and + * write it to file header. */ + if (i == 0) { + mjd += (lastsunset - ptime[i] + 7000.)/86400.0; + period = 7000. + sunset(mjd, sgp4); + FITS_movabs_hdu(outfits, 1, NULL, &status); + FITS_update_key(outfits, TDOUBLE, "ORBPERID", &period, + "[s] Estimate of orbital period", &status); + } + } + /* If we've moved from day into night (or night into day), update + last sunrise/sunset times. */ + else if ((dn_flag == 0) && (dn_flag_last == 1)) + lastsunrise = ptime[i]; + else if ((dn_flag == 1) && (dn_flag_last == 0)) + lastsunset = ptime[i]; + + /* If this is daytime, set the day bit in TFLAG array. */ + if (dn_flag == 0) + tflag[i] |= TEMPORAL_DAY; + + lon[i] = geo_lon; + lat[i] = geo_lat; + vorb[i] = dx; + tsunrise[i] = ptime[i] - lastsunrise; + tsunset[i] = ptime[i] - lastsunset; + dn_flag_last = dn_flag; + } + + + /* + * Set the OPUS flag for times outside of the OPUS good-time + * intervals. Since there are no photons associated with the + * last second of a GTI, we make sure that it is flagged as + * bad. The first second of a good-time interval is good. + */ + j = 0; + for (i = 0; i < ntime; i++) { + while (j < ngti-1 && ptime[i] > gtie[j] - 0.5) + j++; + if (ptime[i] < gtis[j] - FRAME_TOLERANCE || + ptime[i] > gtie[j] + FRAME_TOLERANCE) + tflag[i] |= TEMPORAL_OPUS; + } + tflag[ntime-1] |= TEMPORAL_OPUS; + + /* + * No exposure should be longer than 55 ks. For HIST data, we'll just + * put up with it, but for TTAG data, we'll flag as bad any timeline + * table entries with absurd arrival times. We use the OPUS flag for + * this. What we're really saying is that we don't believe that the + * times associated with these photons are correct. + */ + for (i = 0; i < ntime; i++) + if (ptime[i] > MAX_EXPTIME) + tflag[i] |= TEMPORAL_OPUS; + + /* Fill housekeeping columns (count rates and high voltage). */ + FITS_movabs_hdu(outfits, 1, NULL, &status); + FITS_read_key(outfits, TSTRING, "HKEXISTS", hkexists, NULL, &status); + FITS_read_key(outfits, TSTRING, "DETECTOR", det, NULL, &status); + strncpy(side, det+1, 1); + + /* Populate MIN_LIMB keyword. */ + FITS_update_key(outfits, TDOUBLE, "MIN_LIMB", &min_limb, NULL, &status); + + /* If no housekeeping file exists, use header info to fill timeline. */ + loop: + if(!strncasecmp(hkexists, "N", 1)) { + char cntb_key[FLEN_CARD], cnte_key[FLEN_CARD]; + float cntb, cnte; + float cnt_rate, cnt_rate2, eng_time, exp_time; + double ctimeb, ctimee; + + cf_verbose(1, "No housekeeping file: filling timeline with header info."); + + /* move to the top level header to read the relevant keywords */ + FITS_movabs_hdu(outfits, 1, NULL, &status); + FITS_read_key(outfits, TFLOAT, "EXPTIME", &exp_time, NULL, &status); + FITS_read_key(outfits, TLONG, "NEVENTS", &nevts, NULL, &status); + + /* calculate engineering count rates */ + FITS_read_key(outfits, TDOUBLE, "CTIME_B", &ctimeb, NULL, &status); + FITS_read_key(outfits, TDOUBLE, "CTIME_E", &ctimee, NULL, &status); + eng_time = (ctimee-ctimeb) * 86400.; + + /* If eng_time is unreasonable, use the EXPTIME keyword */ + if (eng_time < 1) { + cf_if_warning("Engineering snapshot time less than or equal to zero."); + if ((eng_time = (mjd_end-mjd_start) * 86400.) < MAX_EXPTIME) + cf_if_warning("Estimating LiF, SiC, FEC and AIC count rates from EXPSTART and EXPEND."); + else { + eng_time = exp_time; + cf_if_warning("Estimating LiF, SiC, FEC and AIC count rates from EXPTIME."); + } + } + + /* SiC count rate timeline */ + sprintf(cntb_key, "C%.2sSIC_B", det); + FITS_read_key(outfits, TFLOAT, cntb_key, &cntb, NULL, &status); + sprintf(cnte_key, "C%.2sSIC_E", det); + FITS_read_key(outfits, TFLOAT, cnte_key, &cnte, NULL, &status); + + if ((cnte<0) || (cntb<0) || (cntb>cnte) || eng_time < 1. || + (cnte==0xEB90EB90) || (cnte==0xDEADDEAD) || + (cntb==0xEB90EB90) || (cntb==0xDEADDEAD) || + ((cnt_rate = (cnte - cntb) / eng_time) > 32000)) { + cf_if_warning("Bad SiC counter. SiC count rate will be set to zero."); + cnt_rate=0; + } + + cf_verbose(2, "SiC count rate = %d", (int) cnt_rate); + for (i=0; icnte) || eng_time < 1. || + (cnte==0xEB90EB90) || (cnte==0xDEADDEAD) || + (cntb==0xEB90EB90) || (cntb==0xDEADDEAD) || + ((cnt_rate = (cnte - cntb) / eng_time) > 32000)) { + cf_if_warning("Bad LiF counter. LiF count rate will be set to zero."); + cnt_rate=0; + } + + cf_verbose(2, "LiF count rate = %d", (int) cnt_rate); + for (i=0; icnte) || eng_time<1 || + (cnte==0xEB90EB90) || (cnte==0xDEADDEAD) || + (cntb==0xEB90EB90) || (cntb==0xDEADDEAD) || + ((cnt_rate = (cnte - cntb) / eng_time) > 64000) || + (cnt_rate < 0.8*nevts/exp_time)) { + cf_if_warning("Bad FEC counter"); + cf_if_warning("-- FEC count rate will be computed from NEVENTS and EXPTIME."); + cf_if_warning("-- Electronic deadtime correction will be underestimated."); + cf_if_warning("-- Y stretch will be underestimated."); + cnt_rate=nevts/exp_time; + } + + cf_verbose(2, "FEC count rate = %d", (int) cnt_rate); + for (i=0; icnte) || (eng_time<1) || + (cnte==0xEB90EB90) || (cnte==0xDEADDEAD) || + (cntb==0xEB90EB90) || (cntb==0xDEADDEAD) || + ((cnt_rate2 = (cnte - cntb)/ eng_time) > 64000)) || + ((!(strncasecmp(dets[i],det,2))) && (cnt_rate2<0.8*nevts/exp_time))) { + cf_if_warning("Bad AIC counter %s",dets[i]); + cf_if_warning("-- AIC count rate will be computed from NEVENTS and EXPTIME."); + cf_if_warning("-- IDS deadtime correction will be underestimated."); + cnt_rate=nevts/exp_time; + break; + } + cnt_rate+=cnt_rate2; + } + + cf_verbose(2, "AIC count rate = %d", (int) cnt_rate); + for (i=0; i vmax) + vmax = hk_colval[j]; + if (vmax <= 0) { + cf_if_warning("Data missing from housekeeping column. " + "Will treat file as missing."); + strncpy(hkexists, "N", 1); + status=0; + goto loop; } + else fill_cntrate_array(nsam_hk, hk_colval, time_hk, ntime, + ptime, siccr);} + else { + cf_if_warning("Data column missing from housekeeping file. " + "Will treat file as missing."); + strncpy(hkexists, "N", 1); + status=0; + goto loop; + } + cf_verbose(3,"SiC count-rate info read from housekeeping file."); + + /* LiF count rate timeline */ + sprintf(cntb_key, "I_DET%.1sCLIF%.1s", det, side); + FITS_get_colnum(hskpfits, TRUE, cntb_key, &hk_colnum, &status); + FITS_read_col(hskpfits, TLONG, hk_colnum, 1L, 1L, nsam_hk, &intnull, + hk_colval, &anynull, &status); + fill_cntrate_array(nsam_hk, hk_colval, time_hk, ntime, ptime, lifcr); + cf_verbose(3,"LiF count-rate info read from housekeeping file."); + + /* FEC count rate timeline */ + sprintf(cntb_key, "I_DET%.1sCFE%.1s", det, side); + FITS_get_colnum(hskpfits, TRUE, cntb_key, &hk_colnum, &status); + FITS_read_col(hskpfits, TLONG, hk_colnum, 1L, 1L, nsam_hk, &intnull, + hk_colval, &anynull, &status); + fill_cntrate_array(nsam_hk, hk_colval, time_hk, ntime, ptime, feccr); + cf_verbose(3,"FEC count-rate info read from housekeeping file."); + + /* AIC count rate timeline */ + aiccr2 = (float *) cf_calloc(ntime, sizeof(float)); + for (j=0;j -1) { + FITS_read_key(outfits, TINT, "DET2HVAH", &hdr_max2a, NULL, &status); + cf_verbose(3, " Max for 2A: header says %d, housekeeping file says %d.", + hdr_max2a, max2a); + if (abs(max2a - hdr_max2a) < 5) + cf_verbose(3, " HV arrays are OK. No need to swap."); + else + swap_HV = TRUE; + } + + /* + * If HV values in file header are bad, compare with expected + * values from VOLT_CAL file. + */ + else { + FITS_open_file(&voltfits, cf_cal_file(volt_cal), READONLY, &status); + n = 0L; + do { + n++; + sprintf(mjd_str, "MJD%ld", n); + FITS_read_key(voltfits, TDOUBLE, mjd_str, &mjd_volt, NULL, &status); + } while (mjd_start > mjd_volt); + n--; + + sprintf(full_str, "FULL%ld", n); + sprintf(saa_str, "SAA%ld", n); + FITS_read_key(voltfits, TINT, full_str, &full, NULL, &status); + FITS_read_key(voltfits, TINT, saa_str, &saa, NULL, &status); + FITS_close_file(voltfits, &status); + + /* If max for 2A matches expected full or SAA voltage -- and + we're on side 2A -- then we're OK. Otherwise, must swap. */ + cf_verbose(3, " 2A max = %d; Expected values for %s: full = %d, SAA = %d", + max2a, det, full, saa); + if ((abs(max2a - full) < 10 || abs(max2a - saa) < 5) && + (*side == 'A')) + cf_verbose(3, " HV arrays are OK. No need to swap."); + else swap_HV = TRUE; + } + } + + /* High voltage timeline */ + if (swap_HV) { + if (*side == 'A') sprintf(cntb_key, "I_DET2HVBIASBST"); + else sprintf(cntb_key, "I_DET2HVBIASAST"); + cf_verbose(3, " Swapping HV values for detectors 2A and 2B"); + } + else sprintf(cntb_key, "I_DET%.1sHVBIAS%.1sST", det, side); + FITS_get_colnum(hskpfits, TRUE, cntb_key, &hk_colnum, &status); + FITS_read_col(hskpfits, TLONG, hk_colnum, 1L, 1L, nsam_hk, &intnull, + hk_colval, &anynull, &status); + if (!hv_from_hskp(nsam_hk, hk_colval, time_hk, ntime, ptime, hv)) + cf_verbose(3,"HV info read from housekeeping file."); + else { + cf_verbose(1,"Housekeeping file corrupted: reading HV info from file header."); + hv_from_header(outfits, det, side, ntime, hv); + } + + free(time_hk); + free(hk_mjd); + free(hk_colval); + FITS_close_file(hskpfits, &status); + } + + /* + * Set TFORM, TSCALE, and TZERO values for output table. + */ + sprintf(fmt_byte, "%ldB", ntime); + sprintf(fmt_float, "%ldE", ntime); + sprintf(fmt_short, "%ldI", ntime); + + /* First set default values. */ + tform[0] = fmt_float; + tform[1] = fmt_byte; + for (i=2; i max_lif) { + lifcr[i] = 0.; + biglif = TRUE; + } + if (siccr[i] > max_sic) { + siccr[i] = 0.; + bigsic = TRUE; + } + if (feccr[i] > max_fec) { + feccr[i] = 0.; + bigfec = TRUE; + } + if (aiccr[i] > max_aic) { + aiccr[i] = 0.; + bigaic = TRUE; + } + } + + if (biglif) cf_if_warning("LIF_CNT_RATE out of bounds. Setting bad values to zero."); + if (bigsic) cf_if_warning("SIC_CNT_RATE out of bounds. Setting bad values to zero."); + if (bigfec) cf_if_warning("FEC_CNT_RATE out of bounds. Setting bad values to zero."); + if (bigaic) cf_if_warning("AIC_CNT_RATE out of bounds. Setting bad values to zero."); + + /* + * Write the timeline table to the output file. + */ + FITS_movabs_hdu(outfits, 3, NULL, &status); + FITS_create_hdu(outfits, &status); + + FITS_create_tbl(outfits, BINARY_TBL, 1L, tfields, ttype, + tform, tunit, extname, &status); + + /* Write TSCALE and TZERO entries to header */ + for (i=2; i 0 && ndx < npix) bpmaskt[ndx] += wt[i] ; + } + } + } + cf_verbose(3, "Channel %d contains %d bad pixels.", ap, nsam) ; + + /* If any potholes are present, generate the pothole map. */ + if(nsam > 0) { + + /* Determine a normalization for the potholes. This is done by + creating a histogram of the weights between 0 and the maximum + and then selecting the 95% level as the normalization factor. + We use 95%, rather than the maximum, to avoid the possibility + of having a few spurious points define the normalization. */ + + /* Determine the maximum value. */ + bpmax = 0.; + for (i=0; i bpmax) bpmax = bpmaskt[i] ; + + /* Generate the histogram. */ + nhist = (int) (bpmax * 10.) + 1 ; + bphist = (int *) cf_calloc(nhist, sizeof(int)) ; + bpsum = 0; + for (i=0; i < npix; i++) { + ndx = (int) (bpmaskt[i] * 10.) ; + if (ndx > 0 && ndx < nhist) { + bphist[ndx]++; + bpsum++; + } + } + + /* Now select the 95% level. */ + nsam = 0; + i = nhist-1 ; + while (nsam < bpsum/20 && i >= 0) { + nsam += bphist[i] ; + pnorm = bpmax - (nhist-1-i) / 10. ; + i--; + } + + cf_verbose(3, "bpmax = %.1f, normalizing factor = %.2f", bpmax, pnorm) ; + + /* Normalize and invert the mask so that the center of the + pothole is zero and the region outside is 1. */ + + for (i=0; i bpmaskt[ndx+1]) + bpmaskt[ndx] = (bpmaskt[ndx-1] + bpmaskt[ndx+1]) / 2.; + } + } + } + + /* If there are no potholes, generate an array with all ones. */ + else + for (i=0; i +#include "calfuse.h" + +static char CF_PRGM_ID[] = "cf_make_wave_array"; +static char CF_VER_NUM[] = "1.5"; + +int +cf_make_wave_array(fitsfile *header, int aperture, long *nout, + float **wave_out) +{ + char parm_file[FLEN_VALUE]; /* Name of parameter file */ + char wave_file[FLEN_VALUE]; /* Name of WAVE_CAL file */ + char w0_key[FLEN_KEYWORD]; /* Depends on aperture */ + char wmax_key[FLEN_KEYWORD]; /* Depends on aperture */ + char wpc_key[FLEN_KEYWORD]; /* Depends on aperture */ + + int status=0, hdunum; + long i; + + float default_w0, default_wmax, default_wpc; /* Default values */ + float w0, wmax, wpc; /* Requested values */ + + fitsfile *parmfits, *wavefits; + + /* Initialize error checking */ + cf_error_init(CF_PRGM_ID, CF_VER_NUM, stderr); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Begin processing"); + + /* + * Set keywords to read either LIF or SIC parameters, depending on + * the aperture number. + */ + if (aperture < 5) { + sprintf(w0_key, "LIF_W0"); + sprintf(wmax_key, "LIF_WMAX"); + sprintf(wpc_key, "LIF_WPC"); + } else { + sprintf(w0_key, "SIC_W0"); + sprintf(wmax_key, "SIC_WMAX"); + sprintf(wpc_key, "SIC_WPC"); + } + + /* Read recommended values of W0, WMAX, and WPC from WAVE_CAL header */ + hdunum = aperture + 1; + FITS_read_key(header, TSTRING, "WAVE_CAL", wave_file, NULL, &status); + FITS_open_file(&wavefits, cf_cal_file(wave_file), READONLY, &status); + FITS_movabs_hdu(wavefits, hdunum, NULL, &status); + FITS_read_key(wavefits, TFLOAT, "W0", &default_w0, NULL, &status); + FITS_read_key(wavefits, TFLOAT, "WMAX", &default_wmax, NULL, &status); + FITS_read_key(wavefits, TFLOAT, "WPC", &default_wpc, NULL, &status); + FITS_close_file(wavefits, &status); + cf_verbose(3, "Recommended wavelength parameters:"); + cf_verbose(3, "\tW0 = %g, WMAX = %g, WPC = %g", + default_w0, default_wmax, default_wpc); + + /* + * Read requested values of W0, WMAX, and WPC from PARM_CAL. + * If no value requested, use default values. + * Compare requested values with default; complain if weird. + */ + FITS_read_key(header, TSTRING, "PARM_CAL", parm_file, NULL, &status); + FITS_open_file(&parmfits, cf_parm_file(parm_file), READONLY, &status); + if (fits_read_key(parmfits, TFLOAT, w0_key, &w0, NULL, &status)) { + w0 = default_w0; + status = 0; + } + else if (w0 < default_w0) + cf_if_warning("Requested value of W0 is less than recommended value."); + + if (fits_read_key(parmfits, TFLOAT, wmax_key, &wmax, NULL, &status)) { + wmax = default_wmax; + status = 0; + } + else if (wmax > default_wmax) + cf_if_warning("Requested value of WMAX is greater than " + "recommended value."); + + if (fits_read_key(parmfits, TFLOAT, wpc_key, &wpc, NULL, &status)) { + wpc = default_wpc; + status = 0; + } + else if (wpc < default_wpc) + cf_if_warning("Requested value of WPC is less than " + "recommended value."); + FITS_close_file(parmfits, &status); + cf_verbose(3, "Using these wavelength parameters:"); + cf_verbose(3, "\tW0 = %g, WMAX = %g, WPC = %g", w0, wmax, wpc); + + /* Compute length of output wavelength array, allocate memory, + * and fill array. + */ + *nout = (long) ((wmax - w0)/wpc + 0.5) + 1L; + *wave_out = (float *) cf_calloc(*nout, sizeof(float)); + for (i = 0; i < *nout; i++) + (*wave_out)[i] = w0 + wpc * (float) i; + + /* + * Write WO and WPC to output file header. + */ + FITS_update_key(header, TFLOAT, "WPC", &wpc, NULL, &status); + FITS_update_key(header, TFLOAT, "W0", &w0, NULL, &status); + + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Done processing"); + return status; +} diff --git a/src/libcf/cf_mirror_motion.c b/src/libcf/cf_mirror_motion.c new file mode 100644 index 0000000..d5dd3b3 --- /dev/null +++ b/src/libcf/cf_mirror_motion.c @@ -0,0 +1,189 @@ +/***************************************************************************** + * Johns Hopkins University + * Center For Astrophysical Sciences + * FUSE + ***************************************************************************** + * + * Synopsis: cf_mirror_motion(header, nevents, time, x, y, channel, + * ntimes, ttime, tsunset) + * + * Description: Calculates the shift of the spectrum in both X and Y caused + * by thermal changes in the mirror position and corrects + * the X and Y coordinates of each photon event. + * + * fitsfile *header Pointer to the location of the FITS + * header of the Intermediate data File + * long nevents Number of photons in the file + * int *time Time stamp (in seconds) since the + * start of the exposure + * float *x Position of the photon (in pixels) + * float *y Position of the photon (in pixels) + * unsigned char channel Channel id of each photon + * long ntimes Number of entries in timeline table + * float ttime Time array of timeline table + * short tsunset Time since last sunset + * + * Returns: 0 on success + * + * History: 09/06/02 1.1 RDR Begin work, adapted from cf_make_shift + * 03/01/03 1.3 wvd Correct use of pointer in FITS_read_key() + * 04/21/03 1.4 wvd Use tsunset array from timeline table. + * Do not assume that ttime is continuous. + * Interpolate between tabulated shifts. + * 05/20/03 1.5 rdr Added call to cf_proc_check + * 08/21/03 1.6 wvd Change channel to unsigned char. + * 06/22/04 1.7 wvd Estimate time between sunsets using + * orbit period in file header. + * 07/14/04 1.8 rdr Correct line which selects calibration + * 03/22/05 1.9 wvd Change tsunset from float to short. + * Read orbital period from file header. + * 04/15/05 1.10 wvd If ORBPERID keyword is not present, + * assume that it is 6000 s. + * 12/20/05 1.11 wvd Omit correction for an extended + * source. + * 04/07/07 1.12 wvd Clean up compiler warnings. + * + ****************************************************************************/ + +#include +#include +#include +#include "calfuse.h" + +int +cf_mirror_motion(fitsfile *header, long nevents, float *time, float *x, + float *y, unsigned char *channel, long ntimes, float *ttime, + short *tsunset) { + + char CF_PRGM_ID[] = "cf_mirror_motion"; + char CF_VER_NUM[] = "1.12"; + + fitsfile *mmfits; + int errflg=0, status=0, anynull=0, hdutype, nullval=0; + int active_ap[2], extended; + long j, k, ndx; + char det[FLEN_VALUE], mmcal[FLEN_VALUE]; + float *tdxlif, *tdxsic, *dxlif, *dylif, *dxsic, *dysic; + float frac, period, w0, w1, w99; + + /* Initialize error checking. */ + cf_error_init(CF_PRGM_ID, CF_VER_NUM, stderr); + + /* Enter a time stamp into the log */ + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Begin Processing"); + + /* Check whether routine is appropriate for this data file. */ + if ((errflg = cf_proc_check(header, CF_PRGM_ID))) return errflg; + + /* Read detector keyword from header. */ + FITS_read_key(header, TSTRING, "DETECTOR", det, NULL, &status); + + /* Determine the channel numbers of the active apertures */ + extended = cf_source_aper(header, active_ap); + + /* If source is extended, exit now. */ + if (extended) { + cf_verbose(1, "Extended source. Omitting photon shift."); + cf_proc_update(header, CF_PRGM_ID, "SKIPPED"); + return (status); + } + + /* + * Read orbital period from file header. + */ + fits_read_key(header, TFLOAT, "ORBPERID", &period, NULL, &status); + if (status) { + status = 0; + period = 6000; + cf_verbose(1, "Keyword ORBPERID not found; assuming 6000 seconds"); + } + else + cf_verbose(2, "Estimated orbital period is %.2f seconds", period); + + /* Allocate space for shift arrays. */ + dxlif = (float *) cf_calloc(ntimes, sizeof(float)); + dylif = (float *) cf_calloc(ntimes, sizeof(float)); + dxsic = (float *) cf_calloc(ntimes, sizeof(float)); + dysic = (float *) cf_calloc(ntimes, sizeof(float)); + + /* Read the name of the mirror-motion calibration file */ + FITS_read_key(header, TSTRING, "MIRR_CAL", mmcal, NULL, &status); + cf_verbose(3, "Mirror motion calibration file = %s", mmcal); + + /* Open the calibration file and read in the information relating + * x shifts as a function of time (in minutes) from sunset for one orbit + * (100 minutes) + */ + FITS_open_file(&mmfits, cf_cal_file(mmcal), READONLY, &status); + tdxsic = (float *) cf_calloc(100, sizeof(float)); + tdxlif = (float *) cf_calloc(100, sizeof(float)); + cf_verbose(3,"detector= %s",det) ; + if (!strncmp(det, "1", 1) ) { + cf_verbose(3,"Correcting detector 1") ; + /* + * NOTE: LiF 1 is used as reference and so, by definition, has no + * mirror motions. Thus, on side 1 only the SiC spectrum will move. + */ + FITS_movabs_hdu(mmfits,2, &hdutype, &status); + FITS_read_img(mmfits, TFLOAT, 1,100, &nullval, tdxsic, &anynull, + &status); + } + else { + cf_verbose(3,"Correcting detector 2") ; + FITS_movabs_hdu(mmfits,3, &hdutype, &status); + FITS_read_img(mmfits, TFLOAT, 1,100, &nullval, tdxlif, &anynull, + &status); + FITS_movabs_hdu(mmfits,4, &hdutype, &status); + FITS_read_img(mmfits, TFLOAT, 1,100, &nullval, tdxsic, &anynull, + &status); + } + FITS_close_file(mmfits, &status); + /* Determine the shifts for each second of the observation. */ + for (k=0; k= 99) { + w99 = 100. - frac; + w0 = frac - 99.; + dxlif[k] = w0 * tdxlif[0] + w99 * tdxlif[99]; + dxsic[k] = w0 * tdxsic[0] + w99 * tdxsic[99]; + } + else { + w0 = (float) (ndx + 1) - frac; + w1 = frac - (float) (ndx); + dxlif[k] = w0 * tdxlif[ndx] + w1 * tdxlif[ndx + 1]; + dxsic[k] = w0 * tdxsic[ndx] + w1 * tdxsic[ndx + 1]; + } + } + + /* Apply the calculated shifts to the data. */ + for (j=k=0; j +#include +#include +#include "calfuse.h" + +int +cf_modify_hist_pha (fitsfile *header, long nevents, unsigned char *pha, + unsigned char *channel) +{ + char CF_PRGM_ID[] = "cf_modify_hist_pha"; + char CF_VER_NUM[] = "1.3"; + + char phahfile[FLEN_FILENAME]; + unsigned char pha_chan[8], *pha_mjd=NULL; + int errflg=0, status=0; + long i, j, jmax; + double expstart, *mjd=NULL; + fitsfile *phahfits; + + cf_error_init(CF_PRGM_ID, CF_VER_NUM, stderr); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Begin Processing"); + + /* If data were not taken in HIST mode, exit now. */ + if ((errflg = cf_proc_check(header, CF_PRGM_ID))) return errflg; + + /* Read header keywords. */ + FITS_read_key(header, TDOUBLE, "EXPSTART", &expstart, NULL, &status); + + /* Open the pulse-height calibration file. */ + FITS_read_key(header, TSTRING, "PHAH_CAL", phahfile, NULL, &status); + cf_verbose(3, "Pulse-height calibration file = %s", phahfile); + FITS_open_file(&phahfits, cf_cal_file(phahfile), READONLY, &status); + + /* + * Loop through all channels, reading expected pulse heights from PHAH_CAL. + * Use the values appropriate for the date of this exposure. + */ + pha_chan[0] = 20; /* Default for events not in a channel */ + for (i = 1; i < 8; i++) { + if (i == 4) continue; + FITS_movabs_hdu(phahfits, i+1, NULL, &status); + jmax = cf_read_col(phahfits, TDOUBLE, "MJD", (void *) &mjd); + jmax = cf_read_col(phahfits, TBYTE, "PHA", (void *) &pha_mjd); + j = 0; + while (j < jmax-1 && mjd[j+1] < expstart) j++; + pha_chan[i] = pha_mjd[j]; + cf_verbose(3, "channel = %d, j = %d, pha = %d", i, j, pha_chan[i]); + } + + /* Close the pulse-height calibration file. */ + FITS_close_file(phahfits, &status); + + /* Set pulse height for each photon according to its channel number. */ + for (j = 0; j < nevents; j++) + pha[j] = pha_chan[(int) channel[j]]; + + free(mjd); + free(pha_mjd); + + cf_proc_update(header, CF_PRGM_ID, "COMPLETE"); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Done processing"); + + return status; +} diff --git a/src/libcf/cf_modify_hist_times.c b/src/libcf/cf_modify_hist_times.c new file mode 100644 index 0000000..ba1b5d0 --- /dev/null +++ b/src/libcf/cf_modify_hist_times.c @@ -0,0 +1,83 @@ +/***************************************************************************** + * Johns Hopkins University + * Center For Astrophysical Sciences + * FUSE + ***************************************************************************** + * + * Synopsis: cf_modify_hist_times (fitsfile *infits, long nevents, + * float *time, GTI *gti); + * + * Description: For histogram data, set photon-arrival times to the midpoint + * of the longest good-time interval. + * + * Arguments: fitsfile *infits Input FITS file pointer + * long nevents Number of photon events + * float *time Time array for photon list + * GIT *gti Good time interval(s) + * + * Calls: + * + * Returns: TRUE if time array is changed. + * FALSE if time array is not changed. + * + * History: 06/02/04 1.1 wvd Initial coding + * 06/07/04 1.2 wvd Use standard return values. + * 02/17/05 1.3 wvd Initalize jmax to 0. + * + ****************************************************************************/ + +#include +#include +#include +#include "calfuse.h" + +int +cf_modify_hist_times (fitsfile *infits, long nevents, float *time, GTI *gti) +{ + char CF_PRGM_ID[] = "cf_modify_hist_times"; + char CF_VER_NUM[] = "1.3"; + + int errflg=0, status=0; + long j, jmax=0; + float exptime, gti_time, max_time, photon_time, rawtime; + + cf_error_init(CF_PRGM_ID, CF_VER_NUM, stderr); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Begin Processing"); + + /* If data were not taken in HIST mode, exit now. */ + if ((errflg = cf_proc_check(infits, CF_PRGM_ID))) return errflg; + + /* Read header keywords. */ + FITS_read_key(infits, TFLOAT, "EXPTIME", &exptime, NULL, &status); + FITS_read_key(infits, TFLOAT, "RAWTIME", &rawtime, NULL, &status); + + /* + * If the entire exposure was rejected by the screening routines, + * we don't bother changing photon-arrival times. If no time was + * lost to screening, the default arrival times are OK. Exit now. + */ + if (exptime < 1. || exptime > rawtime - 1.) { + cf_proc_update(infits, CF_PRGM_ID, "COMPLETE"); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Done processing"); + return -1; + } + + /* Determine which is the longest good-time interval. */ + max_time = 0.; + for (j = 0; j < gti->ntimes; j++) { + if ((gti_time = gti->stop[j] - gti->start[j]) > max_time) { + max_time = gti_time; + jmax = j; + } + } + + /* Set all photon-arrival times to midpoint of longest GTI. */ + photon_time = (gti->start[jmax] + gti->stop[jmax]) / 2.; + for (j = 0; j < nevents; j++) + time[j] = photon_time; + cf_verbose(1, "Setting photon-arrival times to %.1f", photon_time); + + cf_proc_update(infits, CF_PRGM_ID, "COMPLETE"); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Done processing"); + return status; +} diff --git a/src/libcf/cf_nint.c b/src/libcf/cf_nint.c new file mode 100644 index 0000000..8488911 --- /dev/null +++ b/src/libcf/cf_nint.c @@ -0,0 +1,47 @@ +/***************************************************************************** + * Johns Hopkins University + * Center For Astrophysical Sciences + * FUSE + ***************************************************************************** + * + * Synopsis: n = cf_nint(x) + * + * Description: Converts double to nearest integer. + * + * Variables: double x A double + * + * Return: int n Nearest integer + * + * History: 08/25/03 wvd v1.1 Begin work + * 02/09/04 wvd v1.2 Add cf_nlong() + * 02/17/04 wvd v1.3 Test for overflow of int, long + * 02/18/04 wvd v1.4 Change format of error message. + * Change from values.h to limits.h + * + *************************************************************************/ + +#include +#include "calfuse.h" + +int +cf_nint(double x) + +{ + if (x > INT_MAX || x < INT_MIN) + cf_if_error("Cannot convert %10.4e to an integer", x); + + if (x < 0.) return (int) (x - 0.5); + else return (int) (x + 0.5); +} + + +long +cf_nlong(double x) + +{ + if (x > LONG_MAX || x < LONG_MIN) + cf_if_error("Cannot convert %10.4e to a long", x); + + if (x < 0.) return (long) (x - 0.5); + else return (long) (x + 0.5); +} diff --git a/src/libcf/cf_optimal_extraction.c b/src/libcf/cf_optimal_extraction.c new file mode 100644 index 0000000..4bbca9f --- /dev/null +++ b/src/libcf/cf_optimal_extraction.c @@ -0,0 +1,551 @@ +/***************************************************************************** + * Johns Hopkins University + * Center For Astrophysical Sciences + * FUSE + ***************************************************************************** + * + * Synopsis: cf_optimal_extraction(fitsfile *header, int optimal, + * int aperture, float *weight, float *y, unsigned char *channel, + * float *lambda, long ngood, long *good_index, + * float *barray, float *bpmask, int pny, float pycent, + * float *parray, long nout, float *wave_out, float **flux_out, + * float **sigma_out, long **counts_out, float **weights_out, + * float **bkgd_out, short **bpix_out) + * + * Description: Perform standard or optimal extraction of target spectrum. + * + * Note: We use a modified version of the optimal-extraction + * algorithm described by Keith Horne (PASP, 98, 609, 1986). + * + * Arguments: fitsfile *header Pointer to IDF FITS file header + * int optimal TRUE if optimal extraction requested. + * int aperture Target aperture (values 1-8) + * float *weight Scale factor for each photon + * float *y Final y position of each photon + * unsigned char *channel Channel ID of each photon + * float *lambda Wavelength for each photon + * long ngood Length of array good_index + * long *good_index Indices of screened photon events + * float *barray 2-D background array + * (flux-calibrated and binned) + * float *bpmask 2-D array containing bad pixel locations + * Same size and location as the background array + * int pny Size in Y of weights array + * float pycent Y centroid of weights array + * float parray 2-D weights array (binned) + * long nout Length of output arrays + * float *wave_out Output wavelength array + * float **flux_out Output flux array + * float **sigma_out Output error array + * long **counts_out Output counts array + * float **weights_out Output weights array + * float **bkgd_out Output background array + * short **bpix_out Output bad pixel spectrum + * + * Returns: 0 on success + * + * History: 01/28/03 1.1 wvd Initial coding + * 02/28/03 1.2 peb Changed flux_out, var_out, counts_out + * and weight_out argument variables to + * pointer-to-pointers, so the arrays can + * be returned to the calling routine. + * Also tidied the code using lint. + * 03/11/03 1.3 wvd Update documentation regarding use of + * unsigned char + * 03/12/03 1.4 wvd Change weights_out to sum of weights + * 03/19/03 1.5 wvd Divide flux_out and var_out by WPC + * 04/04/03 1.6 rdr - correct bugs in optimum extraction + * - adjust criterion for redetermining + * y centroid + * 05/07/03 1.7 wvd Change ergcm2s to ergcm2 throughout. + * Divide by EXPTIME. Use cf_verbose. + * 05/22/03 1.8 wvd If EXPTIME = 0, set flux and error to 0. + * 05/28/03 1.9 rdr - For HIST data, spread counts + * along the y dimension of + * the data and variance arrays + * - Incorporate the bad pixel mask into + * optimal extraction algorithm + * - Return bad-pixel spectrum + * 09/30/03 1.10 wvd Negative values of YCENT are + * meaningless. Use S/N of data to + * determine significance of YCENT. + * Exclude airglow lines from S/N. + * 10/08/03 1.11 wvd Change counts_out array to type long. + * Add 0.5 to it before rounding. + * Limit Y coordinates of probability + * array before comparing with bkgd. + * 10/31/03 1.12 wvd Read centroid quality flags from IDF + * header. Do not attempt to calculate + * spectral centroid. + * 11/03/03 1.13 wvd Modify calculation of variance estimate. + * Modify scheme for smoothing HIST data. + * Iterate only to 20% accuracy. + * 12/05/03 1.14 wvd Check value of SPECBINY before + * smoothing HIST data in the Y dimension. + * 03/16/04 1.15 wvd In HIST mode, assume counts are + * distributed across one X pixel. + * Delete wave_out -- not used. + * After 50 iterations, abandon optimal + * extraction and use boxcar extraction + * instead. + * Don't test size of barray, + * as it is now the same as parray. + * Change pycent from int to float. + * 04/06/04 1.16 bjg Include string.h + * Remove unused variables + * 04/21/04 1.17 wvd Set dispapix = fabs(dispapix). + * Iterate to 5% accuracy. + * In boxcar extraction, use parray to + * set extraction limits. + * For TTAG data, compute counts_out + * directly from photon list. + * 04/26/04 1.18 wvd Perform all calculations with + * weights array, rather than ergcm2. + * Return counts spectrum. + * Convert from variance to sigma here, + * rather than in cf_write_spectra. + * Iterate to 10% accuracy. + * 05/17/04 1.19 wvd If weights_out[j] = 0, set variance + * = bkgd. Iterate optimal extraction + * to accuracy of 0.01 counts. In boxcar + * extraction, reduce parray limit to + * 1E-4 to better match fluxes from + * optimal extraction for bright stars. + * 08/13/04 1.20 wvd Use QUALITY array to set X limits + * of extraction region. Insure that + * sigma_out array is non-zero. + * 11/22/05 1.21 wvd Scale variance estimate by bad-pixel + * mask to better approximate observed + * counts. + * 06/12/06 1.22 wvd Call cf_verbose rather than + * cf_if_warning. + * + ****************************************************************************/ + +#include +#include +#include +#include +#include + +#include "calfuse.h" + +static char CF_PRGM_ID[] = "cf_optimal_extraction"; +static char CF_VER_NUM[] = "1.22"; + +int +cf_optimal_extraction(fitsfile *header, int optimal, int aperture, + float *weight, float *y, unsigned char *channel, + float *lambda, long ngood, long *good_index, + float *barray, float *bpmask, + int pny, float pycent, float *parray, long nout, float *wave_out, + float **flux_out, float **sigma_out, long **counts_out, + float **weights_out, float **bkgd_out, short **bpix_out) + +{ + char instmode[FLEN_VALUE], yquality_str[FLEN_KEYWORD], + ycent_str[FLEN_KEYWORD], yquality[FLEN_VALUE]; + int status=0; + int nloop; /* Iterations of optimal + extraction loop */ + int ycent_uncertain = FALSE;/* TRUE if centroid quality + less than HIGH */ + + long i, /* index through photon list */ + ii, /* ii = good_index[i] */ + j, /* X index through 2-D arrays */ + jmin, jmax, /* limits of output spectrum */ + k; /* Y index through 2-D arrays */ + + + float exptime, /* exposure time */ + tdead, /* mean dead-time correction */ + w0, /* minimum value of output wave array */ + wpc, /* wavelength increment per output bin */ + *flux_old, /* flux values from previous iteration */ + *flux_box, /* flux values from boxcar extraction */ + *var_out, /* 1-D variance array */ + *var_box, /* variance values from boxcar extraction */ + + ycent; /* Y centroid of target spectrum */ + + double numerator, denominator, /* Used in optimal-extraction calculations */ + var_num, weights_num, + bkgd_num, + *data, /* 2-D data array */ + *variance, /* 2-D variance array */ + *w; /* weights array for variance calculation */ + + int l, lmin, lmax, /* These variables are */ + specbiny, specbiny2; /* are used to smooth */ + float psum, pval; /* HIST data in the */ + double vval; /* Y dimension. */ + + long jj, jjj, m, m_min, n; /* These variables are used to smooth */ + double edge[2], frac[2], x; /* HIST data in the X dimension. */ + double dispapix; /* Mean dispersion per pixel */ + char wave_file[FLEN_VALUE]; /* Name of WAVE_CAL file */ + int hdunum; /* HDU number of WAVE_CAL file */ + fitsfile *wavefits; /* Pointer to WAVE_CAL file */ + + cf_error_init(CF_PRGM_ID, CF_VER_NUM, stderr); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Begin Processing"); + + cf_verbose(3, "Entering cf_optimal_extraction"); + + /* + * Check type of observation (HIST or TTAG) and binning factor. + */ + FITS_movabs_hdu(header, 1, NULL, &status) ; + FITS_read_key(header, TSTRING, "INSTMODE", instmode, NULL, &status); + FITS_read_key(header, TINT, "SPECBINY", &specbiny, NULL, &status); + specbiny2 = specbiny/2 ; + if (specbiny2 < 1) specbiny2 = 1 ; + cf_verbose(3, "Aperture = %d, instrument mode = %s, binning in Y = %d", + aperture, instmode, specbiny) ; + + /* + * Read EXPTIME and TOT_DEAD from file header. + */ + FITS_read_key(header, TFLOAT, "EXPTIME", &exptime, NULL, &status); + FITS_read_key(header, TFLOAT, "TOT_DEAD", &tdead, NULL, &status); + if (tdead < 1.0) tdead = 1.0; + cf_verbose (3, "EXPTIME = %.0f, TOT_DEAD=%g", exptime, tdead); + + /* + * Read wavelength parameters W0 and WPC from file header. + */ + FITS_read_key(header, TFLOAT, "WPC", &wpc, NULL, &status); + FITS_read_key(header, TFLOAT, "W0", &w0, NULL, &status); + cf_verbose (3, "Wavelength info: w0=%g, dw=%g", w0, wpc) ; + + /* + * Read spectral centroid YCENT and YQUAL from file header. + */ + sprintf(ycent_str, "YCENT%1d", aperture); + FITS_read_key(header, TFLOAT, ycent_str, &ycent, NULL, &status); + sprintf(yquality_str, "YQUAL%1d", aperture); + FITS_read_key(header, TSTRING, yquality_str, yquality, NULL, &status); + if (*yquality != 'H') ycent_uncertain = TRUE; + cf_verbose (3, "%s = %g, quality = %s", ycent_str, ycent, yquality); + + /* + * If HIST data, read DISPAPIX from header of WAVE_CAL file. + */ + if (!strncmp(instmode,"H",1)) { + hdunum = aperture + 1; + FITS_read_key(header, TSTRING, "WAVE_CAL", wave_file, NULL, &status); + FITS_open_file(&wavefits, cf_cal_file(wave_file), READONLY, &status); + FITS_movabs_hdu(wavefits, hdunum, NULL, &status); + FITS_read_key(wavefits, TDOUBLE, "DISPAPIX", &dispapix, NULL, &status); + dispapix = fabs(dispapix); + FITS_close_file(wavefits, &status); + } + + /* + * Allocate space for all arrays. + */ + data = (double *) cf_calloc(pny*nout, sizeof(double)); + variance = (double *) cf_calloc(pny*nout, sizeof(double)); + w = (double *) cf_calloc(nout, sizeof(double)); + + flux_old = (float *) cf_calloc(nout, sizeof(float)); + flux_box = (float *) cf_calloc(nout, sizeof(float)); + var_box = (float *) cf_calloc(nout, sizeof(float)); + + *flux_out = (float *) cf_calloc(nout, sizeof(float)); + var_out = (float *) cf_calloc(nout, sizeof(float)); + *counts_out = (long *) cf_calloc(nout, sizeof(long)); + *weights_out = (float *) cf_calloc(nout, sizeof(float)); + *bkgd_out = (float *) cf_calloc(nout, sizeof(float)); + *bpix_out = (short *) cf_calloc(nout, sizeof(short)) ; + + /* + * The quality array (bpix_out) is the product of the probability + * array and the bad-pixel mask. We use it to set the limits of + * the extraction region. + */ + cf_verbose(3, "Generating bad-pixel spectrum.") ; + for (j=0; j 0) { + jmin = j; + break; + } + } + for (j = nout-1; j >= 0; j--) { + if ((*bpix_out)[j] > 0) { + jmax = j+1; + break; + } + } + + /* + * Construct data and variance arrays from photon lists. + * Arrays are pny pixels in Y (to match probability array) + * and nout pixels in X (to match output wavelength array). + * We must thus shift individual photons by PYCENT - YCENT + * pixels in Y. + */ + + cf_verbose(3, "Filling the data array") ; + for (i = 0; i < ngood; i++) { + ii = good_index[i]; + + if (channel[ii] != aperture) continue; + + j = (long) ((lambda[ii] - w0)/wpc + 0.5); + if (j < jmin || j >= jmax) continue; + + k = (long) (y[ii] - ycent + pycent + 0.5); + if (k < 0 || k >= pny) continue; + + if (!strncmp(instmode,"T",1)) { + /* TTAG data */ + (*counts_out)[j]++; + data[k*nout + j] += weight[ii]; + variance[k*nout + j] += weight[ii] * weight[ii]; + } + else { + /* If HIST data are already smoothed in Y, it's easy: */ + if (specbiny == 1) { + data[k*nout + j] += weight[ii]; + variance[k*nout + j] += weight[ii] * tdead; + } + /* If HIST data are binned, smooth in both X and Y dimensions. */ + else { + m_min = 0; + edge[0] = ((double) j - 0.5) * wpc + w0; + edge[1] = ((double) j + 0.5) * wpc + w0; + if ((x = (lambda[ii] - edge[0]) / dispapix) < 0.5) { + frac[0] = 0.5 - x; + frac[1] = 0.5 + x; + jj = j - 1; + n = 2; + if (jj == -1) m_min = 1; + } + else if ((x = (edge[1] - lambda[ii]) / dispapix) < 0.5) { + frac[0] = 0.5 + x; + frac[1] = 0.5 - x; + jj = j; + n = 2; + if (jj + 1 == nout) n = 1; + } + else { + frac[0] = 1.0; + jj = j; + n = 1; + } + + psum = 0.; + vval = weight[ii] * tdead; + lmin = k - specbiny2; + lmax = lmin + specbiny; + if (lmin < 0) lmin = 0; + if (lmax > pny) lmax = pny; + pval = 1. / (lmax - lmin); + for (l = lmin; l < lmax; l++) + psum += parray[l*nout + j]; + for (l = lmin; l < lmax; l++) { + if (psum > 0) pval = parray[l*nout + j] / psum; + for (m = m_min; m < n; m++) { + jjj = jj + m; + data[l*nout + jjj] += pval * frac[m] * weight[ii]; + variance[l*nout + jjj] += pval * frac[m] * vval; + } + } + } + } + } + + /* + * Boxcar extraction. Use parray to set extraction limits in Y. + */ + cf_verbose(3, "Doing the boxcar extraction.") ; + nloop = 0; + for (j = jmin; j < jmax; j++) { + for (k = 0; k < pny; k++) { + if (parray[k*nout + j] > 1E-4) { + (*bkgd_out)[j] += barray[k*nout + j]; + var_out[j] += variance[k*nout + j]; + (*weights_out)[j] += data[k*nout + j]; + } + } + (*flux_out)[j] = (*weights_out)[j] - (*bkgd_out)[j]; + } + + /* + * Has the user requested optimal extraction? + */ + cf_verbose(3,"Optimal keyword = %d ", optimal) ; + if (optimal) { + + /* + * If Y centroid is uncertain, abandon optimal extraction. + */ + if (ycent_uncertain) + cf_verbose(1, "%s uncertain. Cannot perform optimal extraction.", + ycent_str); + + else { /* Proceed with optimal extraction */ + + cf_verbose(3, "Attempting optimal extraction"); + + /* + * Save boxcar versions of flux and variance arrays. + */ + for (j = jmin; j < jmax; j++) { + flux_box[j] = (*flux_out)[j]; + var_box[j] = var_out[j]; + } + + /* + * Need array w[j] to scale the variance estimate. + * w[j] is mean scale factor from counts to weights at each wavelength. + * Must calculate for TTAG data; can use TOT_DEAD for HIST data. + */ + if (!strncmp(instmode,"T",1)) for (j = jmin; j < jmax; j++) { + if ((*counts_out)[j] > 0) { + for (k = 0; k < pny; k++) w[j] += data[k*nout + j]; + w[j] /= (*counts_out)[j]; + } + else w[j] = tdead; + } + else for (j = jmin; j < jmax; j++) w[j] = tdead; + + /* + * Begin big loop. + */ + do { + /* + * Revise variance estimate + * We can omit w[j] here, as it appears in both the numerator + * and denominator of the flux estimate (below). + * 05/17/02 wvd: If weights_out[j] = 0, set variance = bkgd. + * 11/22/05 wvd: Scale variance estimate by bpmask. + */ + for (j = jmin; j < jmax; j++) { + if ((*weights_out)[j] > 0) + for (k = 0; k < pny; k++) + variance[k*nout + j] = bpmask[k*nout + j] * + fabs(parray[k*nout + j] * (*flux_out)[j] + barray[k*nout + j]); + else + for (k = 0; k < pny; k++) + variance[k*nout + j] = bpmask[k*nout + j] * barray[k*nout + j]; + } + + /* + * Optimal extraction + */ + nloop++; + for (j = jmin; j < jmax; j++) { + numerator = denominator = 0.; + for (k = 0; k < pny; k++) if (variance[k*nout+j] > 0) { + numerator += bpmask[k*nout+j] * parray[k*nout + j] * + (data[k*nout + j] - barray[k*nout + j]) / variance[k*nout + j]; + denominator += bpmask[k*nout+j] * parray[k*nout + j] * + parray[k*nout + j] / variance[k*nout + j]; + } + flux_old[j] = (*flux_out)[j]; + if (denominator > 0) (*flux_out)[j] = numerator / denominator; + else (*flux_out)[j] = flux_old[j] = 0. ; + } + + /* + * Repeat loop if any element of flux_out has changed by > 0.01 counts. + */ + for (j = jmin; j < jmax; j++) { + if (fabs((*flux_out)[j]-flux_old[j]) > 0.01) { + cf_verbose(3, "%d\t%d\t%g", nloop, j, (*flux_out)[j]); + break; + } + } + + } while (j < jmax && nloop < 50); /* End of do loop */ + + /* + * If nloop < 50, calculate var_out, weights_out, and bkgd_out. + * Note that we must scale var_out by w[j] here. + */ + if (nloop < 50) { + + memset (*bkgd_out, 0, nout*sizeof(float)); + memset (*weights_out, 0, nout*sizeof(float)); + memset (var_out, 0, nout*sizeof(float)); + + for (j = jmin; j < jmax; j++) { + bkgd_num = weights_num = var_num = denominator = 0.; + for (k = 0; k < pny; k++) if (variance[k*nout+j] > 0) { + bkgd_num += bpmask[k*nout+j] * parray[k*nout + j] * + barray[k*nout + j] / variance[k*nout + j]; + weights_num += bpmask[k*nout+j] * parray[k*nout + j] * + data[k*nout + j] / variance[k*nout + j]; + var_num += bpmask[k*nout+j] * parray[k*nout + j]; + denominator += bpmask[k*nout+j] * parray[k*nout + j] * + parray[k*nout + j] / variance[k*nout + j]; + } + if (denominator > 0) { + (*bkgd_out)[j] = bkgd_num / denominator; + (*weights_out)[j] = weights_num / denominator; + var_out[j] = var_num / denominator * w[j]; + } + else { + (*bkgd_out)[j] = (*weights_out)[j] = var_out[j] = 0.; + } + } + } + /* + * If nloop = 50, use boxcar extraction instead. + */ + else { + cf_verbose(1, "Optimal extraction failed to converge for aperture %d." + " Using boxcar extraction.", aperture); + nloop = 0; + for (j = jmin; j < jmax; j++) { + (*flux_out)[j] = flux_box[j]; + var_out[j] = var_box[j]; + } + } + + } /* End of if/else test of YCENT */ + } /* End of optimal extraction block */ + + /* + * Write number of iterations to file header. + */ + FITS_update_key(header, TINT, "OPT_EXTR", &nloop, NULL, &status); + cf_verbose(2, "Number of iterations in optimal extraction = %d", nloop) ; + + /* Convert error array from variance to sigma. */ + for (j = jmin; j < jmax; j ++) { + if (var_out[j] > 0.) var_out[j] = sqrt(var_out[j]); + else if ((*bkgd_out)[j] > 0.) var_out[j] = sqrt((*bkgd_out)[j]); + else var_out[j] = 0.; + } + *sigma_out = var_out; + + /* + * For HIST data, counts array = weights "uncorrected" for dead time. + */ + if (!strncmp(instmode,"H",1)) for (j = jmin; j < jmax; j++) + (*counts_out)[j] = (long) ((*weights_out)[j] / tdead + 0.5); + + /* + * Clean up + */ + free(data); + free(flux_old); + free(flux_box); + free(var_box); + free(variance); + free(w); + + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Done processing"); + return status; +} diff --git a/src/libcf/cf_pha_x_distort.c b/src/libcf/cf_pha_x_distort.c new file mode 100644 index 0000000..5f58824 --- /dev/null +++ b/src/libcf/cf_pha_x_distort.c @@ -0,0 +1,107 @@ +/***************************************************************************** + * Johns Hopkins University + * Center For Astrophysical Sciences + * FUSE + ***************************************************************************** + * + * Synopsis: cf_pha_x_distort(fitsfile *header, long nevents, + * unsigned char *pha, float *xfarf, + * unsigned char *locflags) + * + * Description: Corrects the X position of low-pulse-height events. + * + * Note: To conform with the CalFUSE standard, the PHAX + * correction is now ADDED to the input photon X coordinate. + * This change from previous versions of the code requires + * a new set of calibration files. The program now checks the + * version number of the PHAX_CAL file and returns an error if + * it is less than 4. + * + * Arguments: fitsfile *header Pointer to FITS file containing the + * header of the intermediate data file + * long nevents The number of events + * unsigned char *pha An array of PHA values + * float *xfarf An array of event X positions + * unsigned char *locflags Location flags of each event + * + * Calls: + * + * Return: 0 on success + * + * History: 11/11/02 1.1 peb Begin work + * 11/12/02 1.3 peb Added check to move only events in + * active region. + * 03/11/03 1.4 wvd Changed pha and locflags to unsigned + * char + * 05/20/03 1.5 rdr Added call to cf_proc_check + * 07/29/03 1.6 wvd If cf_proc_check fails, return errflg. + * 10/14/03 1.7 wvd Add, rather than subtract, PHAX + * correction. Check cal file version. + * 10/17/03 1.8 wvd Don't crash if CALFVERS keyword + * is missing. + * 04/07/07 1.9 wvd Clean up compiler warnings. + * + ****************************************************************************/ + +#include +#include +#include "calfuse.h" + +int +cf_pha_x_distort(fitsfile *header, long nevents, unsigned char *pha, + float *xfarf, unsigned char *locflags) +{ + char CF_PRGM_ID[] = "cf_pha_x_distort"; + char CF_VER_NUM[] = "1.9"; + + char phaxfile[FLEN_VALUE]={'\0'}; + int anynull=0, calfvers, errflg=0, status=0, xlen, ylen; + long j; + float *phax, flt=0.; + fitsfile *phaxfits=NULL; + + cf_error_init(CF_PRGM_ID, CF_VER_NUM, stderr); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Begin Processing"); + + if ((errflg = cf_proc_check(header, CF_PRGM_ID))) return errflg; + + /* + * Read PHA correction (Walk) file + */ + FITS_read_key(header, TSTRING, "PHAX_CAL", phaxfile, NULL, &status); + FITS_open_file(&phaxfits, cf_cal_file(phaxfile), READONLY, &status); + FITS_read_key(phaxfits, TINT, "NAXIS1", &xlen, NULL, &status); + FITS_read_key(phaxfits, TINT, "NAXIS2", &ylen, NULL, &status); + + /* If CALFVERS keyword missing or less than 4, abort pipeline. */ + fits_read_key(phaxfits, TINT, "CALFVERS", &calfvers, NULL, &status); + if (status || calfvers < 4) { + status = 0; + FITS_close_file(phaxfits, &status); + cf_if_error("Old versions of PHAX_CAL have wrong sign. Aborting."); + } + + /* Otherwise, read walk correction as an image. */ + phax = (float *) cf_malloc(sizeof(float)*xlen*ylen); + FITS_read_img(phaxfits, TFLOAT, 1L, xlen*ylen, &flt, phax, &anynull, &status); + FITS_close_file(phaxfits, &status); + + if (xlen != NXMAX) + cf_if_warning("NAXIS1 of %s != 16384", phaxfile); + /* + * Apply PHA X correction to each event. + */ + for(j=0; j +#include +#include "calfuse.h" + + +int cf_proc_check(fitsfile *fptr, char *prog_id) +{ + char comment[FLEN_CARD], instmode[FLEN_CARD]; + char key_value[FLEN_CARD]; + int j=0, errflg=0, status=0; + + /* The calfuse.h file contains the definitions of keyword_tab, + * NUM_PROC_STEPS, and CALIBRATION_STEP_KEYS. + */ + struct keyword_tab keytab[NUM_PROC_STEPS]=CALIBRATION_STEP_KEYS; + + FITS_read_key(fptr, TSTRING, "INSTMODE", instmode, comment, &status); + + switch (instmode[0]) { + case 'H': + /* Histogram mode */ + /* First, determine if this procedure is even supposed to be + * run on this data. */ + + while ((strncmp(keytab[j].hist_proc,prog_id, + strlen(keytab[j].hist_proc)) != 0) && + (j < NUM_PROC_STEPS)) j++; + if (j < NUM_PROC_STEPS) + cf_verbose(3, "cf_proc_check: prog_id=%s, key=%s, j=%d, value=%s", + prog_id, keytab[j].hist_proc, j, keytab[j].hist_value) ; + if ((j >= NUM_PROC_STEPS) || + (strncmp(keytab[j].hist_value, "PERFORM", 7))) { + cf_verbose(1, "Not appropriate for HIST data. Exiting."); + errflg=1; + } + + break; + + case 'T': + /* Time-tag mode */ + /* First, determine if this procedure is even supposed to be + * run on this data. */ + while ((strncmp(keytab[j].ttag_proc,prog_id, + strlen(keytab[j].ttag_proc)) != 0) && + (j < NUM_PROC_STEPS)) j++; + if (j < NUM_PROC_STEPS) + cf_verbose(3, "cf_proc_check: prog_id=%s, key=%s, j=%d, value=%s", + prog_id, keytab[j].ttag_proc, j, keytab[j].ttag_value) ; + if ((j >= NUM_PROC_STEPS) || + (strncmp(keytab[j].ttag_value, "PERFORM", 7))) { + cf_verbose(1, "Not appropriate for TTAG data. Exiting."); + errflg=1; + } + + break; + + default: + errflg = 1; + } + + if (!errflg) { + /* Check to see whether user wants to skip this step. */ + FITS_read_key(fptr, TSTRING, keytab[j].name, key_value, comment, + &status); + if (!strncmp(key_value, "OMIT", 4) || !strncmp(key_value, "SKIPPED", 7)) { + cf_verbose(1, "Header keyword %s = %s. Exiting.", + keytab[j].name, key_value); + FITS_update_key(fptr, TSTRING, keytab[j].name, "SKIPPED", NULL, + &status); + errflg=1; + } + + /* Now check to see if the step has already been completed. */ + if (!strncmp(key_value, "COMPLETE", 7)) { + cf_if_warning("Exiting.\n\t%s has already been run on this file.", + prog_id); + errflg=1; + } + } + return errflg; +} diff --git a/src/libcf/cf_proc_update.c b/src/libcf/cf_proc_update.c new file mode 100644 index 0000000..2e15d29 --- /dev/null +++ b/src/libcf/cf_proc_update.c @@ -0,0 +1,97 @@ +/***************************************************************************** + * Johns Hopkins University + * Center For Astrophysical Sciences + * FUSE + ***************************************************************************** + * + * Synopsis: cf_proc_update(fitsfile *fptr, char *prgm_id, char *key_value) + * + * Description: cf_proc_update will update the FITS header keyword + * which corresponds to the given prgm_id in the file + * fptr to the value given in key_value. + * + * Arguments: fitsfile *fptr Pointer to input file + * char *prgm_id Procedure name + * char *key_value Updated procedure status + * + * History: 05/21/98 emm Begin work. + * 05/21/98 emm finished + * 06/17/98 emm Modified so that the keyword_tab + * structure is read from ed_calfuse.h + * file, which simplifies revisions in + * the order of processing. + * 09/08/99 peb Added lines to update NEXTEND keyword + * 01/31/00 emm Added update to DATE keyword. + * 04/01/03 wvd Changed cf_errmsg to cf_if_warning, + * fits_modify_key_str to FITS_update_key, + * fits_read_key_str to FITS_read_key + * 12/18/03 bjg Change calfusettag.h to calfuse.h + * 04/07/07 1.5 wvd Delete CF_PRGM_ID, as it is not used. + * + ****************************************************************************/ + +#include +#include +#include "calfuse.h" + +int cf_proc_update(fitsfile *fptr, char *prgm_id, char *key_value) +{ + + char comment[FLEN_CARD], instmode[FLEN_CARD]; + int i, status=0, hdutype=0, nextend; + /* + * The calfuse.h file contains the definitions of keyword_tab + * NUM_PROC_STEPS, and CALIBRATION_STEP_KEYS. + */ + struct keyword_tab keytab[NUM_PROC_STEPS]=CALIBRATION_STEP_KEYS; + + FITS_movabs_hdu(fptr, 1, &hdutype, &status); + FITS_get_num_hdus(fptr, &nextend, &status); + nextend -= 1; + FITS_update_key(fptr, TINT, "NEXTEND", &nextend, NULL, &status); + + FITS_read_key(fptr, TSTRING, "INSTMODE", instmode, comment, &status); + + FITS_write_date(fptr, &status); + + switch (instmode[0]) { + case 'H': + /* Find the keyword associated with prgm_id by looping + * through keytab[i].hist_proc */ + i=0; + while ((strncmp(keytab[i].hist_proc,prgm_id, + strlen(keytab[i].hist_proc)) != 0) && + (i < NUM_PROC_STEPS)) i++; + if (i < NUM_PROC_STEPS) { + /* We found a match to prgm_id, so change the associated + * keyword in the header. */ + FITS_update_key(fptr, TSTRING,keytab[i].name,key_value, NULL, &status); + } else { + /* The given prgm_id did not match any of the known + * keytab[i].hist_proc, so return 1. */ + cf_if_warning("No PROCESSING STEP keyword is defined for %s", prgm_id); + return 1; + } + break; + case 'T': + /* Timetag mode */ + /* Find the keyword associated with prgm_id by looping + * through keytab[i].ttag_proc */ + i=0; + while ((strncmp(keytab[i].ttag_proc,prgm_id, + strlen(keytab[i].ttag_proc)) != 0) && + (i < NUM_PROC_STEPS)) i++; + if (i < NUM_PROC_STEPS) { + /* We found a match to prgm_id, so change the associated + * keyword in the header. */ + FITS_update_key(fptr, TSTRING,keytab[i].name,key_value, NULL, &status); + } else { + /* The given prgm_id did not match any of the known + * keytab[i].ttag_proc, so return 1. */ + cf_if_warning("No PROCESSING STEP keyword is defined for %s", prgm_id); + return 1; + } + break; + } + return status; +} diff --git a/src/libcf/cf_read_fpa_pos.c b/src/libcf/cf_read_fpa_pos.c new file mode 100644 index 0000000..87e8099 --- /dev/null +++ b/src/libcf/cf_read_fpa_pos.c @@ -0,0 +1,82 @@ +/***************************************************************************** + * Johns Hopkins University + * Center For Astrophysical Sciences + * FUSE + ***************************************************************************** + * + * Synopsis: cf_read_fpa_pos (fitsfile *infits, float *fpaxsic, float *fpaxlif) + * + * Description: Returns SiC and LiF FPA positions in microns. Can read both + * old and new FPA position keywords. + * + * Arguments: fitsfile *infile Input data file name + * float *fpaxsic FPA SiC position (returned) + * float *fpaxlif FPA LiF position (returned) + * + * Returns: int status CFITSIO status value + * + * History: 08/21/01 v1.1 wvd Subroutine taken from cf_wfits.c + * 01/14/03 v1.3 wvd Change name to cf_read_fpa_pos. + * 12/18/03 v1.4 bjg Change calfusettag.h to calfuse.h + * + ****************************************************************************/ + +#include +#include "calfuse.h" + +/* for all FPA's an increase in "data number" moves the FPA towards +Xipcs */ +#define FPALIF1DN2X0 -69.949 /* DN to microns conversion, zero-point */ +#define FPALIF1DN2X1 .14144 /* DN to microns conversion, linear term */ +#define FPALIF2DN2X0 -73.189 /* DN to microns conversion, zero-point */ +#define FPALIF2DN2X1 .14487 /* DN to microns conversion, linear term */ +#define FPASIC1DN2X0 -132.507 /* DN to microns conversion, zero-point */ +#define FPASIC1DN2X1 .14156 /* DN to microns conversion, linear term */ +#define FPASIC2DN2X0 -89.116 /* DN to microns conversion, zero-point */ +#define FPASIC2DN2X1 .14206 /* DN to microns conversion, linear term */ + +int cf_read_fpa_pos (fitsfile *infits, float *fpaxsic, float *fpaxlif) +{ + char detector[FLEN_VALUE]; /* detector keyword from FITS header */ + int status=0; + float tmpxsic, tmpxlif; + + FITS_read_key(infits, TSTRING, "DETECTOR", detector, NULL, &status); + + /* Get FPA positions */ + /* Use ffgky instead of FITS_read_key so we can read either the old + * or new FPA position keywords */ + ffgky (infits, TFLOAT, "FPASXPOS", fpaxsic, NULL, &status); + if (status != 0) { + /* New keywords are not present; must be the old ones. + * Determine which detector provided current spectrum + * and convert raw FPA position to microns. + */ + status = 0; + if (strncmp(detector,"1", 1)==0) { + FITS_read_key (infits, TFLOAT, "FP1SXPOS", &tmpxsic, NULL, + &status); + FITS_read_key (infits, TFLOAT, "FP1LXPOS", &tmpxlif, NULL, + &status); + *fpaxsic = FPASIC1DN2X0 + FPASIC1DN2X1 * tmpxsic; + *fpaxlif = FPALIF1DN2X0 + FPALIF1DN2X1 * tmpxlif; + } + else if (strncmp(detector,"2", 1)==0) { + FITS_read_key (infits, TFLOAT, "FP2SXPOS", &tmpxsic, NULL, + &status); + FITS_read_key (infits, TFLOAT, "FP2LXPOS", &tmpxlif, NULL, + &status); + *fpaxsic = FPASIC2DN2X0 + FPASIC2DN2X1 * tmpxsic; + *fpaxlif = FPALIF2DN2X0 + FPALIF2DN2X1 * tmpxlif; + } + else { + cf_if_error("Could not parse DETECTOR keyword, cannot " + "convert raw FPA positions."); + } + } + else { + /* New SiC FPA keyword present. Assume new LiF FPA keyword + * is also present */ + FITS_read_key(infits, TFLOAT, "FPALXPOS", fpaxlif, NULL, &status); + } + return status; +} diff --git a/src/libcf/cf_rebin_background.c b/src/libcf/cf_rebin_background.c new file mode 100644 index 0000000..23e15f3 --- /dev/null +++ b/src/libcf/cf_rebin_background.c @@ -0,0 +1,211 @@ +/***************************************************************************** + * Johns Hopkins University + * Center For Astrophysical Sciences + * FUSE + ***************************************************************************** + * + * Synopsis: cf_rebin_background(infits, aperture, nout, wave_out, + * binx, biny, bnx, bny, bimage, barray) + * + * Arguments: *fitsfile infits : Input IDF file + * int aperture : Aperture ID for the analysis + * long nout : Length of wave_out array + * float wave_out : Wavelength vector + * int binx, biny : Binning factors of the background array + * int bnx, bny : X and Y dimension of the background array + * float bimage : 2-D background image (original) + * float barray : (OUTPUT) Binned background image. + * + * Description: + * + * The input background image is binned in X. + * We need an image binned in wavelength. + * To get it, we use the WAVE_CAL file (shifted to account + * for the FPA position) to derive a wavelength array for the + * background image. For each row in the background image (bimage), + * we build a second image (barray) scaled to the size of the output + * wavelength bins. + * + * History 02/21/03 v1.1 rdr Started work + * 04/01/03 v1.2 rdr Made aeff arrays double precision in + * the cf_read_fluxcal routine to be + * compatible with data in calfiles + * 05/07/03 v1.4 wvd Don't divide by EXPTIME. + * Read WPC from file header. + * Use cf_verbose. + * 06/02/03 v1.5 rdr Correct bug in filling output arrays + * 06/11/03 v1.7 wvd Pass datatype to cf_read_col. + * Change calfusettag.h to calfuse.h + * 08/22/03 v1.8 bjg Move get_extraction_limits to external + * subroutine. Free orphan arrays. + * Change coltype from char to int in + * cf_read_col. + * 08/28/03 v1.9 wvd Debug + * 09/29/03 v1.10 wvd Shift background model to match + * position of FPA. + * 03/16/04 v1.11 wvd Correct error in calculation of dw_ave + * and dweff. + * 04/05/04 v1.12 wvd Modify i/o. + * 04/26/04 v1.13 wvd Do not flux-calibrate 2-D background + * model. Do not extract 1-D background + * spectrum. + * 05/13/04 v1.14 wvd Correct value of CF_PRGM_ID. + * 07/21/04 v1.16 wvd Delete unused variables. + * + *****************************************************************************/ + +#include +#include +#include +#include +#include "calfuse.h" + + +int cf_rebin_background(fitsfile *infits, int aperture, long nout, + float *wave_out, int binx, int biny, int bnx, int bny, + float *bimage, float **barray) { + + char CF_PRGM_ID[] = "cf_rebin_background"; + char CF_VER_NUM[] = "1.16"; + + fitsfile *wavefits ; + int status=0; + int dndx, dpix, nyout; + long npix, npix_out, nwave, ndx, ndx1, ndx2; + long i, j, k; + float dwb, dw_out, mf, ctot, dw_ave; + float dpix_fpa; + float *wave, *wavet, *outarr; + char wavefile[FLEN_VALUE], det[FLEN_VALUE] ; + + /* Initialize error checking */ + cf_error_init(CF_PRGM_ID, CF_VER_NUM, stderr); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Started execution."); + + /* Read wavelength spacing of the output array */ + FITS_read_key(infits, TFLOAT, "WPC", &dw_out, NULL, &status) ; + cf_verbose(3, "Bin size of the output wavelength array = %5.3f A", + dw_out) ; + FITS_read_key(infits, TSTRING, "DETECTOR", det, NULL, &status) ; + cf_verbose(3,"Detector = %s, aperture = %d", det, aperture) ; + + /* Read wavelength-calibration file */ + FITS_read_key(infits, TSTRING, "WAVE_CAL", wavefile, NULL, &status) ; + cf_verbose(3, "Wavelength calibration file = %s",wavefile) ; + FITS_open_file(&wavefits, cf_cal_file(wavefile), READONLY, &status) ; + cf_verbose(3, "HDU to read = %d",aperture+1) ; + FITS_movabs_hdu(wavefits, aperture +1, NULL, &status) ; + nwave=cf_read_col(wavefits,TFLOAT,"WAVELENGTH",(void **) &wave); + cf_verbose(3, "Points read = %d, min & max: %4.2f, %4.2f", + nwave, wave[0], wave[nwave-1]); + + /* Read pixel shifts due to FPA positions */ + if (aperture < 5) + FITS_read_key(infits, TFLOAT, "FPADXLIF", &dpix_fpa, NULL, &status); + else + FITS_read_key(infits, TFLOAT, "FPADXSIC", &dpix_fpa, NULL, &status); + dpix = cf_nint(dpix_fpa); + + /* To correct for the position of the FPA, each photon has been shifted + in X by dpix pixels. Rather than shifting the background to match, + we modify the wavelength array that maps the background onto the + output spectrum. */ + cf_verbose(2, "Shifting aperture %d background by %d X pixels " + "to match the FPA shift.", aperture, cf_nint(dpix_fpa)); + + /* Generate a new wavelength array binned to match the background array */ + cf_verbose(3, "X and Y binning factors for background array = %d, %d", + binx, biny) ; + + wavet = (float *) cf_calloc(bnx, sizeof(float)); + for (i = 0; i < bnx; i++) { + ndx=i * binx + (binx/2) + dpix; + if (ndx > nwave-1) ndx = nwave-1 ; + if (ndx < 0) ndx = 0; + wavet[i] = wave[ndx]; + } + + /* Error check: average wavelength spacing */ + dw_ave = fabs(wavet[bnx-1]-wavet[0])/(bnx-1); + cf_verbose(3,"Average wavelength spacing of background array = %f", dw_ave) ; + + if ((aperture < 4 && strncmp(det,"1",1) == 0) || + (aperture > 4 && strncmp(det,"2",1) == 0)) { + cf_verbose(3, "Maximum tabulated wavelength = %.2f", wavet[bnx-1]); + cf_verbose(3, "Maximum of wave_out = %.2f", wave_out[nout-1] ); + } + else { + cf_verbose(3, "Maximum tabulated wavelength = %.2f", wave_out[nout-1] ); + cf_verbose(3, "Maximum of wave_out = %.2f", wave_out[nout-1] ); + } + + /* Define some sizes and allocate space for the output arrays */ + nyout = bny * biny ; /* Y dimension of output 2-D bkgd array */ + npix_out = nout * nyout ; /* Size of output 2-D bkgd array */ + npix = bnx * bny ; /* Size of input 2-D bkgd array */ + outarr = (float *) cf_calloc(npix_out, sizeof(float) ); /* 2-D output array */ + + /* Error check: total counts in the background image */ + ctot=0.; + for (i=0; i 4 && strncmp(det,"1",1) == 0 ) ) { + ndx = bnx - 1 ; + dndx = -1 ; + } + + cf_verbose(3,"Filling output: starting ndx=%d, increment =%d ", ndx, dndx) ; + + dwb = dw_ave; + for (i=0; i= 0) ndx += dndx ; + + /* compute the relative + wavelength coverage of the background and output arrays */ + if (ndx < bnx-2) dwb = fabs((double) (wavet[ndx+1]-wavet[ndx])) ; + mf = dw_out/dwb ; + /* correct the scale factor for binning in y */ + mf /= biny ; + /* populate the column of the array */ + for (j=0; j< nyout ; j++) { + k = j/biny ; + ndx1 = j*nout + i ; + if (ndx1 > npix_out-1) ndx1 = npix_out-1 ; + ndx2 = k*bnx + ndx ; + if (ndx2 > npix-1) ndx2=npix-1 ; + outarr[ndx1] = mf * bimage[ndx2] ; + } + } + + + /* Error checking: total counts in the background image */ + ctot=0.; + for (i=0; i +#include +#include +#include +#include "calfuse.h" + +int cf_rebin_probability_array(fitsfile *infits, int extended, int aperture, + long nout, float *wave_out, int *pny, float *pycent, float **parray) +{ + + char CF_PRGM_ID[] = "cf_rebin_probability_array"; + char CF_VER_NUM[] = "1.10"; + + fitsfile *wgtsfits, *wavefits ; + int status=0, fpixel=1, nullval=0, anynull=0 ; + int hdu, nxwt, nywt, dndx, wtbin; + long npix, npix_out, nwave, ndx, ndx1, ndx2, i, j ; + float *wave, *wavet, *wgts_arr, *ynorm, *outarr ; + float total, wgt_cent ; + char wgtsfile[FLEN_VALUE]={'\0'}, wavefile[FLEN_VALUE]={'\0'} ; + char buffer[FLEN_CARD], det[FLEN_CARD] ; + + /* Initialize error checking */ + cf_error_init(CF_PRGM_ID, CF_VER_NUM, stderr); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Started execution."); + + /* Read calibration file names from the IDF file header. */ + FITS_movabs_hdu(infits, 1, NULL, &status) ; + FITS_read_key(infits, TSTRING, "WGTS_CAL", wgtsfile, NULL, &status) ; + cf_verbose(3,"weights cal file = %s ",wgtsfile) ; + FITS_read_key(infits, TSTRING, "WAVE_CAL", wavefile, NULL, &status) ; + cf_verbose(3, "wavelength cal file = %s ",wavefile) ; + FITS_read_key(infits, TSTRING, "DETECTOR", det, NULL, &status) ; + cf_verbose(3,"Detector = %s ",det) ; + + /* Open the weights file and read the array */ + FITS_open_file(&wgtsfits, cf_cal_file(wgtsfile), READONLY, &status) ; + hdu = extended * 8 + aperture + 1; + cf_verbose(3, "WGTS_CAL: extended = %d, aperture = %d, hdu = %d", + extended, aperture, hdu); + FITS_movabs_hdu(wgtsfits, hdu, NULL, &status) ; + FITS_read_key(wgtsfits, TINT, "NAXIS1", &nxwt, buffer, &status) ; + FITS_read_key(wgtsfits, TINT, "NAXIS2", &nywt, buffer, &status) ; + FITS_read_key(wgtsfits, TFLOAT, "WGT_CENT", &wgt_cent, buffer, &status) ; + npix=nxwt * nywt ; + cf_verbose(3, "prob array: nx=%d, ny=%d, wgt_cent=%f ",nxwt, nywt, wgt_cent); + wgts_arr = (float *) calloc(npix, sizeof(float)) ; + FITS_read_img(wgtsfits, TFLOAT, fpixel, npix, &nullval, wgts_arr, + &anynull, &status) ; + FITS_close_file(wgtsfits, &status) ; + + /* Read the wavelength array */ + FITS_open_file(&wavefits, cf_cal_file(wavefile), READONLY, &status) ; + FITS_movabs_hdu(wavefits, aperture +1, NULL, &status) ; + nwave=cf_read_col(wavefits,TFLOAT,"WAVELENGTH", (void **) &wave); + FITS_close_file(wavefits, &status) ; + + /* Determine the binning factor for the weights and generate a new + wavelength array that corresponds to the binning factor used. */ + wtbin = NXMAX / nxwt ; + cf_verbose(3, "Binning factor for weights array = %d ", wtbin) ; + wavet = (float *) cf_calloc(nxwt, sizeof(float) ) ; + for (i=0; i nwave-1) ndx = nwave-1 ; + if (ndx < 0) ndx = 0 ; + wavet[i] = wave[ndx] ; + } + + /* Allocate space for the output array */ + npix_out = nout * nywt ; + if ((aperture < 4 && strncmp(det,"1",1) == 1) || + (aperture > 4 && strncmp(det,"2",1) == 1)) + cf_verbose(3, "maximum tabulated wavelength = %g, " + "maximum of wave_out=%g", wavet[nxwt-1],wave_out[nout-1] ); + else + cf_verbose(3, "maximum tabulated wavelength = %g, " + "maximum of wave_out=%g", wavet[0],wave_out[nout-1] ); + outarr = (float *) cf_calloc(npix_out, sizeof(float)) ; + + /* Fill in the output array - use the weight profile which is closest + to the individual wavelengths in the output wavelength array. + Remember : the Lif channels and the SiC channels have wavelengths + that run in opposite directions, e.g. for side 1 wavelengths + increase with index for Lif but decrease for SiC. The opposite is + true for side 2. */ + + ndx=0 ; + dndx = 1 ; + if ((aperture < 4 && strncmp(det,"2",1) == 0) || + (aperture > 4 && strncmp(det,"1",1) == 0 ) ) { + ndx = nxwt - 1 ; + dndx = -1 ; + } + + cf_verbose(3, "filling output: starting index = %d, increment = %d ", + ndx, dndx) ; + + for (i=0; i= 0 ) + ndx += dndx ; + /* populate the column of the array */ + for (j=0; j npix_out-1) ndx1 = npix_out-1 ; + ndx2 = j*nxwt + ndx ; + if (ndx2 > npix-1) ndx2=npix-1 ; + outarr[ndx1] = wgts_arr[ndx2] ; + } + } + + /* Adjust the probabilities so that the integral along y at every + wavelength position is 1 */ + + /* First sum the points along y (ynorm) at each point */ + ynorm= (float *) cf_calloc(nout, sizeof(float)) ; + for (i=0; i 0.1) + for (j=0; j +#include +#include +#include +#include "calfuse.h" + +int +cf_satellite_jitter(fitsfile *infits, long nevents, float *time, + float *x, float *y, unsigned char *channel, long nsec, + float *ttime, unsigned char *status_flag) +{ + char CF_PRGM_ID[] = "cf_satellite_jitter"; + char CF_VER_NUM[] = "1.31"; + + fitsfile *jitfits, *parmfits; + char det[FLEN_VALUE]; + char jitr_cal[FLEN_VALUE], parmfile[FLEN_VALUE]; + char comment[FLEN_COMMENT]; + short c, *trkflg, trkflg_min; + int active_ap[2], extended, status=0, hdutype; + long j, k, njitr, nrej, *time_jit, time_diff; + double data_expstart, jitr_expstart; + float *dx_jit, *dy_jit, x_factor, y_factor; + float *dx_tt, *dy_tt; + float factor[2][4] = {{1.743,1.743,-1.743, -1.743}, + {1.154,1.163,-0.6335,-0.581}}; + + /* Initialize error checking */ + cf_error_init(CF_PRGM_ID, CF_VER_NUM, stderr); + + /* Enter a time stamp into the log */ + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Begin Processing"); + + /* Read exposure start time from IDF header */ + FITS_read_key(infits, TDOUBLE, "EXPSTART", &data_expstart, NULL, &status); + + /* If APER_COR is not set to "COMPLETE", exit now. */ + FITS_read_key(infits, TSTRING, "APER_COR", comment, NULL, &status); + if (strncmp(comment, "COMPLETE", 8)) { + cf_verbose(1, "APER_COR = %s. Omitting photon shift.", comment); + cf_proc_update(infits, CF_PRGM_ID, "SKIPPED"); + return (status); + } + + /* If target is an extended source, exit now. */ + extended = cf_source_aper(infits, active_ap); + if (extended) { + cf_verbose(1, "Extended source. Omitting photon shift."); + cf_proc_update(infits, CF_PRGM_ID, "SKIPPED"); + return (status); + } + + /* Determine the scale factor to convert arcseconds to pixels. */ + FITS_read_key(infits, TSTRING, "DETECTOR", det, NULL, &status); + c = det[0] =='2'? 2: 0; + if (det[1] == 'B') + c++; + x_factor=factor[0][c]; + y_factor=factor[1][c]; + + /* Update the PLATESC (plate scale) keyword in the header */ + FITS_update_key(infits, TFLOAT, "PLATESC", &y_factor, NULL, &status); + + cf_verbose(3, "Arcsec to pixels: X = %5.3f\tY = %5.3f", + x_factor, y_factor); + + /* Try to open the jitter file. */ + FITS_read_key(infits, TSTRING, "JITR_CAL", jitr_cal, NULL, &status); + fits_open_file(&jitfits, jitr_cal, READONLY, &status); + + /* If the jitter file is not found, try a lower-case filename. */ + if (status != 0) { + status = 0; + jitr_cal[0] = (char) tolower(jitr_cal[0]); + fits_open_file(&jitfits, jitr_cal, READONLY, &status); + } + + /* Read exposure start time from jitter file header */ + FITS_read_key(jitfits, TDOUBLE, "EXPSTART", &jitr_expstart, NULL, &status); + + /* Allocate space for correction arrays */ + dx_tt = (float *) cf_calloc(nsec, sizeof(float)); + dy_tt = (float *) cf_calloc(nsec, sizeof(float)); + + /* Read the jitter file. */ + FITS_movabs_hdu(jitfits, 2, &hdutype, &status); + njitr=cf_read_col(jitfits, TLONG, "TIME", (void **) &time_jit); + njitr=cf_read_col(jitfits, TFLOAT, "DX", (void **) &dx_jit); + njitr=cf_read_col(jitfits, TFLOAT, "DY", (void **) &dy_jit); + njitr=cf_read_col(jitfits, TSHORT, "TRKFLG", (void **) &trkflg); + FITS_close_file(jitfits, &status); + + /* Read minimum acceptable TRKFLG value from PARM_CAL file */ + FITS_read_key(infits, TSTRING, "PARM_CAL", parmfile, NULL, &status); + FITS_open_file(&parmfits, cf_parm_file(parmfile), READONLY, &status); + FITS_read_key(parmfits, TSHORT, "TRKFLG", &trkflg_min, NULL, &status); + FITS_close_file(parmfits, &status); + + /* Correct for difference in data and jitter EXPSTART times */ + time_diff = cf_nlong((data_expstart - jitr_expstart) * 86400.); + for (j=0; j< njitr; j++) time_jit[j] -= time_diff; + + /* + * Map times in the jitter file to times in the timeline table + * and calculate the jitter offsets. + */ + for (j=k=0; k < nsec; k++) { + while ((float) time_jit[j+1] < ttime[k] && j+1 < njitr) j++; + if (trkflg[j] >= trkflg_min) { + dx_tt[k] = x_factor * dx_jit[j]; + dy_tt[k] = y_factor * dy_jit[j]; + } + } + /* + * Map times in the timeline table to the times associated + * with individual photons and apply the appropriate shifts. + * Move only photons in the active aperture and for which the + * timeline status jitter flag has not been set. + * Record number of rejected events. + * Note: active_ap[0] = lif, active_ap[1] = sic + */ + nrej = 0; + for (j=k=0; j +#include +#include +#include +#include "calfuse.h" + + +/********************************************************************* + * + * GET_XVAR_IMG + * + * Subroutine to compute the intensity variation along the X direction + * of a background image. Pixels flagged as bad are excluded. + * bkgimg = image from which to extract the data + * maskimg = mask for data image (1 = good pixel) + * nxb = size of bkgimg in x + * nxsam = number of elements in the xvars array + * xvars = array of x variations + * + ***********************************************************************/ + + +int +get_xvar_img(float *bkgimg, float *maskimg, int nxb, int nxsam, float *xvars) +{ + int nbin; + long i, j; + + nbin = nxb/nxsam ; + for (i = 0; i < NYMAX; i++) + for (j = 0; j < nxb; j++) + xvars[j/nbin] += bkgimg[i*nxb+j] * maskimg[i*nxb+j]; + + return 0 ; +} + +/********************************************************************* + * + * MAKE_MODEL + * + * Subroutine to combine a day and night calibration image to generate the + * final background model: + * npix = number of pixels in the full background image + * nsam = number of pixels in the background regions of the detector + * nxb = size of the x dimension of the background images + * intcr = assumed intrinsic count rate + * expnight, expday = exposure times during the night and day + * data_sum_night, data_sum_day = sum of weights within the background + * sample regions for night and day exposures + * model_sum_night, model_sum_day = number of counts in the unscaled + * night and day background calibration images + * - background regions only + * bkgimgn = image containing the night calibration image. + * bkgimgd = image containing the daytime calibration image + * bkgimg = final background image + * maskimg = mask defining good background regions + * + *****************************************************************************/ + +int +make_model(long npix, long nsam, int nxb, float intcr, float expnight, + float expday, double data_sum_night, double data_sum_day, + double model_sum_night, double model_sum_day, + float *bkgimgn, float *bkgimgd, float *bkgimg, float *maskimg) +{ + int bin_size ; + long i; + float int_counts; + float sfd, sfn, intnight, intday, scatnight, scatday ; + + /* bin_size = binning factor of the background image */ + bin_size = NXMAX / nxb ; + + cf_verbose(3, "\n\tConstructing the background model\n") ; + cf_verbose(3, "total counts in the data: night= %.1f, day = %.1f", + data_sum_night, data_sum_day); + cf_verbose(3, "intrinsic count rate = %.2f x 10^-7 ",intcr ) ; + cf_verbose(3, "exptime night = %.1f, exptime day = %.1f ", + expnight, expday ); + + /* Sum the intrinsic background counts */ + intnight = nsam * bin_size * intcr * expnight * 1.e-7 ; + intday = nsam * bin_size * intcr * expday * 1.e-7 ; + cf_verbose(3, "total intrinsic counts: night= %.1f , day= %.1f ", + intnight, intday) ; + + /* Sum of scattered light in data (measured - intrinsic) */ + scatnight = data_sum_night - intnight ; + if (scatnight <= 0.) scatnight = 0. ; + scatday = data_sum_day - intday ; + if (scatday <= 0.) scatday = 0. ; + cf_verbose(3, "total scattered light count: night = %.1f, day = %.1f", + scatnight, scatday); + cf_verbose(3, "total counts in unscaled background model: " + "night = %.2f, day = %.2f", model_sum_night, model_sum_day); + + /* Calculate the scale factor for the night scattered light image */ + sfn = 0. ; + if (model_sum_night > 0) sfn = scatnight / model_sum_night ; + + /* Calculate the scale factor for the day scattered light image */ + sfd = 0. ; + if (model_sum_day > 0) sfd = scatday / model_sum_day ; + cf_verbose(3, "scale factors for background images: " + "night = %.1f, day = %.1f ", sfn, sfd) ; + + /* Calculate the intrinsic counts per binned pixel */ + int_counts = bin_size * intcr * (expnight + expday) * 1.e-7 ; + cf_verbose(3, "intrinsic counts per binned pixel = %.6f ", int_counts ) ; + + /* Use the scattered light scaling factors and the tabulated intrinsic + count rate to model the final background image */ + + for (i = 0; i < npix; i++) + bkgimg[i] = (sfn * bkgimgn[i]) + (sfd * bkgimgd[i]) + int_counts; + + return 0 ; +} + + +/********************************************************************* + * + * MAKE_MODEL_EXPTIME : + * + * Subroutine to combine a day and night calibration image based on + * exposure times only to generate the final background model: + * npix = total number of pixels in the image + * nxb = length of the x axis in the background images + * intcr = assumed intrinsic count rate + * expnight, expday = exposure times during the night and day + * bkging = image containing the night calibration image. + * bkgimgd = image containing the daytime calibration image + * bkgimg = final background model + * + *********************************************************************/ + + +int +make_model_exptime(long npix, int nxb, float intcr, float expnight, + float expday, float *bkgimgn, float *bkgimgd, float *bkgimg) +{ + + int i, bin_size ; + float intnight, intday ; + + /* Compute the binning factor in x */ + bin_size = NXMAX/nxb ; + + /* Calculate the expected intrinsic counts in the background */ + intnight = bin_size * intcr * expnight * 1.e-7 ; + intday = bin_size * intcr * expday * 1.e-7 ; + + /* Combine the day and night images based on exposure times */ + for (i=0 ; i 0) { + maskimg[ndx] = 0. ; + n_air++ ; + } + } + } + + free(gxmin); + free(gxmax); + free(gymin); + free(gymax); + + cf_verbose(3, "Number of bkgd pixels affected by geocoronal lines = %ld", + n_air) ; + + /* Count up and return the number of good pixels. */ + n_good = 0; + for (i = 0; i < npix; i++) if(maskimg[i] > 0) n_good++; + cf_verbose(3, "Number of bkgd pixels flagged as good = %ld", n_good) ; + + *nsam = n_good; + return 0 ; +} + + +/****************************************************************************** + * + * GET_LIMITS + * + * Set limits of background subimage to match those of probability array. + * + * + ******************************************************************************/ + +int get_limits(fitsfile *infits, int extended, int aperture, + int *ymin, int *ymax) +{ + + char wgtsfile[FLEN_VALUE], ycentname[FLEN_KEYWORD]; + int hdu, nywt, status=0; + float ycentv, wgt_cent; + fitsfile *wgtsfits; + + cf_verbose(3, "Determining Y limits for aperture %d background array.", + aperture); + + /* Read the measured centroid of the target spectrum. */ + sprintf(ycentname,"YCENT%1d", aperture); + FITS_movabs_hdu(infits, 1, NULL, &status); + FITS_read_key(infits, TFLOAT, ycentname, &ycentv, NULL, &status); + + /* Read the centroid and size of the probability array. */ + FITS_read_key(infits, TSTRING, "WGTS_CAL", wgtsfile, NULL, &status); + FITS_open_file(&wgtsfits, cf_cal_file(wgtsfile), READONLY, &status); + hdu = extended * 8 + aperture + 1; + cf_verbose(3, "WGTS_CAL: extended = %d, aperture = %d, hdu = %d", + extended, aperture, hdu); + FITS_movabs_hdu(wgtsfits, hdu, NULL, &status); + FITS_read_key(wgtsfits, TINT, "NAXIS2", &nywt, NULL, &status); + FITS_read_key(wgtsfits, TFLOAT, "WGT_CENT", &wgt_cent, NULL, &status); + FITS_close_file(wgtsfits, &status); + + cf_verbose(3, "Spectrum centroid=%6.2f, weights centroid=%5.2f, " + "weights ny=%4d", ycentv, wgt_cent, nywt) ; + + /* Note that we allow these values to exceed the limits of the + * detector. This is required if the bkgd arrays are to cover + * the same area as the 2-D probability and data arrays. */ + + *ymin = cf_nint (ycentv - wgt_cent); + *ymax = *ymin + nywt - 1; + + return status ; +} + + +/********************************************************************* + * + * SUM_GOOD_PIXELS + * + * Subroutine multiplies image and mask arrays, then sums the result. + * image = image from which to extract the data + * mask = mask for data image (1 = good pixels) + * npix = size of image and mask arrays + * + ***********************************************************************/ + + +int +sum_good_pixels(float *image, float *mask, long npix, double *image_sum) +{ + + long i; + + *image_sum = 0; + + for (i = 0; i < npix; i++) + *image_sum += image[i] * mask[i]; + + return 0 ; +} + + +/****************************************************************************** + * + * MAIN PROGRAM BEGINS HERE + * + ******************************************************************************/ + + +int cf_scale_bkgd(fitsfile *infits, long nevents, float *x_in, float *y_in, + float *w_in, unsigned char *channel, unsigned char *timeflags, + unsigned char *locflags, long ngood, long *good_index, long dtime, + long ntime, int *binx, int *biny, int *nx_lif, int *ny_lif, + int *ymin_lif, float **img_lif, int *nx_sic, int *ny_sic, int *ymin_sic, + float **img_sic) +{ + + char CF_PRGM_ID[] = "cf_scale_bkgd"; + char CF_VER_NUM[] = "1.25"; + + fitsfile *bkgdfits, *scrnfits, *bchrfits, *parmfits ; + char buffer[FLEN_CARD], bkgdfile[FLEN_CARD], scrnfile[FLEN_CARD]; + char bchrfile[FLEN_CARD], keyname[FLEN_CARD], parmfile[FLEN_CARD] ; + char run_bkgd[FLEN_VALUE]; + char comment[FLEN_CARD], datestr[FLEN_CARD]; + int nx, nxb, ny, status, hdutype, frow, felem, niter; + int src_ap[2], nullval, anynull, bkgd_num; + int ymin, ymax, phalow, nbinx, nxsam, bkgdtype ; + int bin_size, extended, keyval, timeref; + double data_sum_day, data_sum_night, data_sum; + double model_sum_night, model_sum_day, model_sum ; + float *xvarg, *bkgarr, *xvars0, *xvarm0 ; + float *bkgimg, *bkgimgd, *bkgimgn, *xvars, *xvarm; + float floatnull, exptime, expnight, expday, xvars_ave ; + float intcrarray[9], intcr, scattot, rms, rms0, dcr ; + float intcnt, scat_int_ratio, zero, mf, numtot, xvars_tot, xvarm_tot ; + float *dataimg, *maskimg; + short *ylim ; + long fpixel, npix, i, j, k, nsam; + long nbgood, npts, ndx, ndx1, ndx2, bkgd_ndx; + + /* Initialize error checking */ + cf_error_init(CF_PRGM_ID, CF_VER_NUM, stderr); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Started execution."); + + /* Initialize CFITSIO variables */ + anynull = 0 ; + hdutype = 0 ; + frow = 1 ; + felem = 1 ; + floatnull = 0. ; + fpixel = 1 ; + status = 0 ; + + /* Initialize other variables */ + data_sum_day=0.; + data_sum_night=0.; + zero = 0.; + + /* Open parameter file and check whether user wants a background model. */ + FITS_movabs_hdu(infits, 1, &hdutype, &status) ; + FITS_read_key(infits, TSTRING, "PARM_CAL", parmfile, NULL, &status) ; + cf_verbose(3, "parameter file is %s ", parmfile) ; + FITS_open_file(&parmfits,cf_parm_file(parmfile), READONLY, &status) ; + FITS_read_key(parmfits, TSTRING, "RUN_BKGD", run_bkgd, NULL, &status) ; + FITS_close_file(parmfits, &status) ; + cf_verbose(3, "RUN_BKGD = %s", run_bkgd) ; + + /* If the RUN_BKGD = NO, then fill background array with zeros. */ + if (!strncmp(run_bkgd, "N", 1) || !strncmp(run_bkgd, "n", 1)) { + cf_verbose(1, "RUN_BKGD = NO. No background subtraction.") ; + FITS_write_comment(infits, " ", &status); + FITS_write_comment(infits, "RUN_BKGD = NO. No background subtraction.", + &status); + fits_get_system_time(datestr, &timeref, &status); + sprintf(comment, "CalFUSE v%s %.10s", CALFUSE_VERSION, datestr); + FITS_write_comment(infits, comment, &status); + FITS_write_comment(infits, " ", &status); + + bin_size = 1 ; + nx=nxb=NXMAX ; + ny=NYMAX ; + npix=nx * ny ; + bkgimg = (float *) cf_calloc(npix, sizeof(float)) ; + goto fin ; + } + +/*********************************************************************** + * + * Set up the parameters for the analysis + * + ***********************************************************************/ + + /* Set day and night exposure times */ + expday = (float) dtime ; + expnight = (float) ntime ; + exptime = expday + expnight ; + + /* Get name of background characterization file */ + FITS_read_key(infits, TSTRING, "BCHR_CAL",bchrfile, NULL, &status) ; + cf_verbose(3, "BCHR parameter file is %s ",bchrfile) ; + + /* Get name of background calibration file */ + FITS_read_key(infits, TSTRING, "BKGD_CAL", bkgdfile, buffer, &status); + cf_verbose(3,"Background calibration file = %s ",bkgdfile ) ; + + /* Get name of screening file */ + FITS_read_key(infits, TSTRING, "SCRN_CAL",scrnfile, NULL, &status) ; + cf_verbose(4, "screening file is %s ",scrnfile) ; + + /* Read pha screening limit from the input file header */ + FITS_read_key(infits,TINT,"PHALOW",&phalow, NULL, &status) ; + if (phalow > 8) phalow=8 ; + cf_verbose(2, "pha screening limit = %d", phalow) ; + + /* Determine the type of background model to make by checking the + BKGDTYPE flag in the screening file. If BKGDTYPE > 0, do a full + model. If BKGDTYPE < 0, calculate a model based on exposure time. */ + FITS_open_file(&scrnfits,cf_parm_file(scrnfile), READONLY, &status) ; + FITS_read_key(scrnfits, TINT, "BKGDTYPE",&bkgdtype, NULL, &status) ; + FITS_close_file(scrnfits, &status) ; + + /* Read the intrinsic count rate from the BCHR file */ + FITS_open_file(&bchrfits,cf_parm_file(bchrfile), READONLY, &status) ; + FITS_movabs_hdu(bchrfits, 3, &hdutype, &status) ; + FITS_read_img(bchrfits, TFLOAT, fpixel, 9, &nullval, intcrarray, + &anynull, &status) ; + FITS_close_file(bchrfits, &status) ; + intcr=intcrarray[phalow] ; + cf_verbose(2,"Initial guess for the intrinsic count rate = " + "%.1f x 10^-7 c/s/pixel ", intcr) ; + + /* Read the limits of the background sample regions from the header + of the input file */ + FITS_read_key(infits, TINT, "BKGD_NUM", &bkgd_num, NULL, &status) ; + cf_verbose(3, "Number of background sample regions = %d ", bkgd_num) ; + + ylim = (short *) cf_calloc(bkgd_num*2, sizeof(short) ) ; + for (i=0; i 1) for (i=0; i= NYMAX) continue; + bkgd_ndx = j*nxb + cf_nint(x_in[ndx])/bin_size; + if (maskimg[bkgd_ndx] > 0) { + dataimg[bkgd_ndx] += w_in[ndx]; + if (timeflags[ndx] & TEMPORAL_DAY) data_sum_day += w_in[ndx] ; + else data_sum_night += w_in[ndx]; + nbgood++ ; + } + } + + cf_verbose(3, "Number of photons events in the background region = %ld", + nbgood); + cf_verbose(3, "Sum of daytime weights = %.1lf ", data_sum_day) ; + cf_verbose(3, "Sum of nighttime weights = %.1lf ", data_sum_night) ; + + /* If the background scattered light contribution is too large, the + background may be contaminated, perhaps by a source in one of the + other apertures. This is common in crowded fields or with nebulocity. + In this case, we calculate the background model based on the + exposure times, as done for the histogram data */ + + /* Check the level of the scattered-light background */ + intcnt = intcr * nsam * bin_size * exptime * 1.e-7 ; + scattot = data_sum_day + data_sum_night - intcnt ; + scat_int_ratio = 0. ; + if (intcnt > 0) scat_int_ratio = scattot / intcnt ; + cf_verbose(3, "int cnt = %.1f, scat cnt = %.1f , scat/int = %f ", + intcnt, scattot, scat_int_ratio) ; + + if (scat_int_ratio > 10) { + cf_verbose(1, "The scattered light background is too large."); + bkgdtype = -1; + } + else { + cf_verbose(2, + "Scattered light appears reasonable. Proceeding with analysis.") ; + } + + } /* Analysis of the data ends here. */ + + /* If the background model is to be calculated using only the exposure + time, then do it now. */ + if (bkgdtype < 0) { + cf_verbose(1, "Constructing background based only on exposure time.") ; + make_model_exptime( npix, nxb, intcr, expnight, expday, + bkgimgn, bkgimgd, bkgimg) ; + goto fin ; + } + +/**************************************************************************** + * + * In this section, we attempt to determine the intrinsic count rate. + * The scattered light shows little structure in the Y dimension, so + * we project all of the arrays onto the X axis. Only good pixels + * in the user-specified background regions are included in the sum. + * + ****************************************************************************/ + + /* Make a scattered light reference image assuming an intrinsic count + rate of zero. */ + make_model_exptime(npix, nxb, zero, expnight, expday, + bkgimgn, bkgimgd, bkgimg) ; + + /* We bin the data by another factor of 8 in X */ + /* nbinx = number of detector pixels in one bin */ + /* nxsam = number of samples in the array */ + nbinx=128 ; + nxsam = NXMAX/nbinx ; + cf_verbose(3, "X variation array information: " + "nbinx = %d, nxsam= %d ", nbinx, nxsam) ; + + xvars = (float *) cf_calloc(nxsam,sizeof(float)) ; + xvarm = (float *) cf_calloc(nxsam,sizeof(float)) ; + xvars0 = (float *) cf_calloc(nxsam,sizeof(float)) ; + xvarm0 = (float *) cf_calloc(nxsam,sizeof(float)) ; + xvarg = (float *) cf_calloc(nxsam,sizeof(float)) ; + + /* Project each image onto the X axis */ + get_xvar_img(bkgimg, maskimg, nxb, nxsam, xvarm0) ; + get_xvar_img(dataimg, maskimg, nxb, nxsam, xvars0) ; + get_xvar_img(maskimg, maskimg, nxb, nxsam, xvarg) ; + + /* Calculate the average counts per "good" bin in the data array. */ + xvars_ave = 0; + for (i = j = 0; i < nxsam; i++) + if (xvarg[i] > 0) { + xvars_ave += xvars0[i]; + j++; + } + xvars_ave /= j; + cf_verbose (3, "xvars_ave = %.1f (should be > 100)", xvars_ave); + + /* If the average number of counts in the xvars0 array (which holds + the observed intensity variation along the x direction) is small, + then we can't determine an intrinsic count rate from the data and + we use the tabulated rate. If the count is large enough, then we + can do a more detailed fit of the model to the observations. */ + + if (xvars_ave > 100) { /* Begin fit to intrinsic background */ + + cf_verbose(1, "Calculating a full background model.") ; + cf_verbose(3, "\n\tInterpolating to derive intrinsic count rate\n") ; + + /* Sum the counts in the data and model arrays. */ + sum_good_pixels(dataimg, maskimg, npix, &data_sum); + sum_good_pixels(bkgimg, maskimg, npix, &model_sum); + + cf_verbose(3, "Total counts in initial scattered-light model = %7.0lf", + model_sum); + cf_verbose(3, "Intrinsic counts summed over good regions = %7.0f", + (intcnt = intcr * nsam * bin_size * exptime * 1.e-7)); + cf_verbose(3, "Sum of above = %7.0lf", + model_sum + intcnt); + cf_verbose(3, "Total counts in good regions of data array = %7.0lf", + data_sum); + + /* Sum the counts in the data and model x variation arrays */ + xvarm_tot = 0.; + xvars_tot = 0.; + for (i = j = 0; i < nxsam; i++) if (xvarg[i] > 0) { + xvarm_tot += xvarm0[i]; + xvars_tot += xvars0[i]; + } + cf_verbose(3, "Total counts in scattered-light xvar array = %7.0f", + xvarm_tot); + cf_verbose(3, "Total counts in data x variation array = %7.0f", + xvars_tot); + + /* Convert the x variation arrays from total counts to units of + 1.e-7 c/s/pix, the units of the intrinsic count rate. */ + mf = bin_size * exptime * 1.e-7 ; + for (i=0 ; i 0) { + xvars0[i] /= xvarg[i] * mf ; + xvarm0[i] /= xvarg[i] * mf ; + } + + /* Sum the counts in the rescaled xvar arrays */ + xvarm_tot = 0.; + xvars_tot = 0.; + for (i = j = 0; i < nxsam; i++) if (xvarg[i] > 0) { + xvars_tot += xvars0[i]; + xvarm_tot += xvarm0[i]; + j++; + } + cf_verbose(3, "Mean xvar count rates in units of 10^-7 c/s/pixel:"); + cf_verbose(3, " Initial model = %.1f", xvarm_tot/j); + cf_verbose(3, " Intrinsic counts = %.1f", intcr); + cf_verbose(3, " Data array = %.1f", xvars_tot/j); + + /* Determine the value of the intrinsic background by comparing the X + variations of the data (after removing a guess for the intrinsic + background) with the model scattered light variations, making sure + that the final average count rate is the same for both. Iterate + until the intrinsic background changes by less than 0.1 units. */ + + dcr = 1. ; + niter = 0 ; + rms0 = 1.e10 ; + while ( fabs(dcr) > 0.1) { + + /* Subtract intrinsic counts from the data array and sum it. */ + xvars_tot = 0. ; + for (i=0; i 0) { + xvars[i] = xvars0[i] - intcr ; + xvars_tot += xvars[i] ; + } + + /* Scale the model array to match the data. Sum it. */ + numtot = 0. ; + for (i=0 ; i 0) { + xvarm[i] = xvarm0[i] * (xvars_tot / xvarm_tot) ; + numtot += xvarm[i] ; + } + + /* Sum the absolute difference between the data and model arrays. */ + rms = 0. ; + for (i=0 ; i 0) + rms += (fabs(xvars[i]-xvarm[i])) ; + cf_verbose(3, "intr cr= %5.2f, data-model = %6.2f, " + "dat cnts = %5.0f, mod cnts=%5.0f", intcr,rms,xvars_tot,numtot) ; + + niter++ ; + if (niter > 20) break ; + + /* if the current rsm value is greater than the preceeding one, + reverse direction and reduce the step size by 50% */ + if ( rms > rms0 ) dcr = -0.5*dcr ; + intcr += dcr ; + + /* initialize the next iteration */ + rms0 = rms ; + } + } /* End of fit to intrinsic background */ + + else { + cf_verbose(1, "Background count too small for a detailed fit."); + cf_verbose(1, "Assuming an intrinsic count rate of %.1f cts/s", intcr ) ; + } + + /* Sum the good pixels in the unscaled day and night background images. */ + sum_good_pixels(bkgimgn, maskimg, npix, &model_sum_night); + sum_good_pixels(bkgimgd, maskimg, npix, &model_sum_day); + + /* Make the final background model */ + make_model(npix, nsam, nxb, intcr, expnight, expday, + data_sum_night, data_sum_day, model_sum_night, model_sum_day, + bkgimgn, bkgimgd, bkgimg, maskimg) ; + + /* Sum the counts in the final background image. */ + sum_good_pixels(bkgimg, maskimg, npix, &model_sum); + + cf_verbose(3, "Total counts in final background model = %.0lf", model_sum); + cf_verbose(3, " measured counts = %.0lf", + data_sum_day+data_sum_night); + + free(bkgimgn) ; + free(bkgimgd) ; + free(dataimg) ; + free(maskimg) ; + free(xvars) ; + free(xvars0) ; + free(xvarm) ; + free(xvarm0) ; + free(xvarg) ; + + fin: + + /************************************************************************** + * + * Extract the subarrays covering the active LiF and SiC apertures + * + ***************************************************************************/ + + extended = cf_source_aper(infits, src_ap) ; + cf_verbose(3, "\n\tSelecting subarrays\n") ; + cf_verbose(3, "source apertures: lif=%d, sic=%d ",src_ap[0], src_ap[1]) ; + + /* Populate some output values */ + *binx=bin_size ; + *biny=1 ; + + for (k=0; k<2 ; k++) { /* Loop over LiF and SiC channels */ + + /* Read the y limits for the output array */ + get_limits(infits, extended, src_ap[k], &ymin, &ymax) ; + + /* Set up array to contain the image */ + npts = nxb * (ymax-ymin+1) ; + bkgarr = (float *) cf_calloc(npts, sizeof(float)) ; + + /* Fill the array */ + ndx1 = -1 ; + model_sum = 0 ; + for (i=ymin; i<=ymax ; i++) { + if (i < 0 || i >= ny) + ndx1 += nxb ; + else { + for (j=0; j= npix) break ; + ndx1++; + if (ndx1 >= npts) break ; + bkgarr[ndx1]=bkgimg[ndx2] ; + model_sum += bkgarr[ndx1] ; + } + } + } + + /* Populate the output arrays and values */ + if (k == 0) { + *nx_lif = nxb ; + *ny_lif = (ymax - ymin + 1) ; + *ymin_lif = ymin ; + *img_lif = bkgarr ; + } + else { + *nx_sic = nxb ; + *ny_sic = (ymax - ymin + 1) ; + *ymin_sic = ymin ; + *img_sic = bkgarr ; + } + + cf_verbose(2, "for aperture %d, nx=%d, ny=%d, ymin=%d, model_sum=%.0f", + src_ap[k], nxb, (ymax-ymin+1), ymin, model_sum) ; + + } /* End loop over LiF and SiC channels */ + + /* release memory for the background image */ + free(bkgimg) ; + + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Finished execution."); + return 0; +} diff --git a/src/libcf/cf_screen_airglow.c b/src/libcf/cf_screen_airglow.c new file mode 100644 index 0000000..5a7b2b3 --- /dev/null +++ b/src/libcf/cf_screen_airglow.c @@ -0,0 +1,70 @@ +/***************************************************************************** + * Johns Hopkins University + * Center For Astrophysical Sciences + * FUSE + ***************************************************************************** + * + * Synopsis: cf_screen_airglow (fitsfile *header, long nevents, + * float *x, float *y, unsigned char *location) + * + * Description: Flag photon events in airglow regions. + * + * Arguments: fitsfile *header Input FITS file pointer + * long nevents Number of photon events + * float *x X coordinate array + * float *y Y coordinate array + * unsigned char *location Photon location flag array + * + * Calls: cf_get_geocorona + * + * Returns: 0 on success + * + * History: 03/10/05 1.1 wvd Initial coding + * + ****************************************************************************/ + +#include +#include "calfuse.h" + +int +cf_screen_airglow (fitsfile *header, long nevents, float *x, float *y, + unsigned char *location) +{ + char CF_PRGM_ID[] = "cf_screen_airglow"; + char CF_VER_NUM[] = "1.1"; + + int errflg=0, ngeo; + long i, j; + short *gxmin, *gxmax, *gymin, *gymax; + + cf_error_init(CF_PRGM_ID, CF_VER_NUM, stderr); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Begin Processing"); + if ((errflg = cf_proc_check(header, CF_PRGM_ID))) return errflg; + + /* + * Read limits of airglow regions from AIRG_CAL file. + */ + ngeo = cf_get_geocorona(header, &gxmin, &gxmax, &gymin, &gymax); + + /* + * Set the airglow bit of photons in the airglow regions. + */ + for (i = 0; i < nevents; i++) { + for (j=0; j gxmin[j] && x[i] < gxmax[j] && + y[i] > gymin[j] && y[i] < gymax[j] ) { + location[i] = location[i] | LOCATION_AIR; + break; + } + } + } + + free(gxmin); + free(gxmax); + free(gymin); + free(gymax); + + cf_proc_update(header, CF_PRGM_ID, "COMPLETE"); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Done processing"); + return 0; +} diff --git a/src/libcf/cf_screen_bad_pixels.c b/src/libcf/cf_screen_bad_pixels.c new file mode 100644 index 0000000..99884a5 --- /dev/null +++ b/src/libcf/cf_screen_bad_pixels.c @@ -0,0 +1,122 @@ +/***************************************************************************** + * Johns Hopkins University + * Center For Astrophysical Sciences + * FUSE + ***************************************************************************** + * + * Synopsis: cf_screen_bad_pixels (fitsfile *header, long nevents, + * float *x, float *y, unsigned char *location) + * + * Description: Flag photon events in bad-pixel regions. + * + * Arguments: fitsfile *header Input FITS file pointer + * long nevents Number of photon events + * float *x X coordinate array + * float *y Y coordinate array + * unsigned char *location Photon location flag array + * + * Calls: cf_get_potholes + * + * Returns: 0 on success + * + * History: 11/22/05 1.1 wvd Initial coding + * + ****************************************************************************/ + +#include +#include "calfuse.h" + +/*********************************************************************** + * + * Procedure to read pothole locations from the QUAL_CAL file + * + ***********************************************************************/ + +int +cf_get_potholes(fitsfile *header, float **xbad, float **ybad, + float **rxbad, float **rybad) +{ + char qualfile[FLEN_VALUE]; + int nbad, status=0; + fitsfile *qualfits; + + cf_verbose(3, "Entering cf_get_potholes."); + + /* + * Read limits of bad-pixel regions from the first extension + * of the QUAL_CAL file. + */ + FITS_movabs_hdu(header, 1, NULL, &status); + FITS_read_key(header, TSTRING, "QUAL_CAL", qualfile, NULL, &status); + cf_verbose(3, "QUAL_CAL = %s", qualfile); + + FITS_open_file(&qualfits, cf_cal_file(qualfile), READONLY, &status); + FITS_movabs_hdu(qualfits, 2, NULL, &status); + nbad = cf_read_col(qualfits, TFLOAT, "X", (void **) xbad); + nbad = cf_read_col(qualfits, TFLOAT, "Y", (void **) ybad); + nbad = cf_read_col(qualfits, TFLOAT, "RX", (void **) rxbad); + nbad = cf_read_col(qualfits, TFLOAT, "RY", (void **) rybad); + FITS_close_file(qualfits, &status); + + cf_verbose(3, "Exiting cf_get_potholes."); + return nbad; +} + + +int +cf_screen_bad_pixels (fitsfile *header, long nevents, float *x, float *y, + unsigned char *location) +{ + char CF_PRGM_ID[] = "cf_screen_bad_pixels"; + char CF_VER_NUM[] = "1.1"; + + int errflg=0, nbad; + long counter=0, i, j; + float *xbad, *ybad, *rxbad, *rybad, *rx2, *ry2; + + cf_error_init(CF_PRGM_ID, CF_VER_NUM, stderr); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Begin Processing"); + if ((errflg = cf_proc_check(header, CF_PRGM_ID))) return errflg; + + /* + * Read limits of bad-pixel regions from QUAL_CAL file. + */ + nbad = cf_get_potholes(header, &xbad, &ybad, &rxbad, &rybad); + cf_verbose(2, "For first pothole: x = %.0f, y = %.0f, rx = %.0f, ry = %.0f", + xbad[0], ybad[0], rxbad[0], rybad[0]); + + /* + * Square the semi-major axes. + */ + for (j = 0; j < nbad; j++) { + rxbad[j] *= rxbad[j]; + rybad[j] *= rybad[j]; + } + rx2 = rxbad; + ry2 = rybad; + cf_verbose(2, "For first pothole: rx2 = %.0f, ry2 = %.0f", rx2[0], ry2[0]); + + /* + * Flag photons in the bad-pixel regions. + */ + for (i = 0; i < nevents; i++) { + for (j = 0; j < nbad; j++) { + if ((x[i] - xbad[j]) * (x[i] - xbad[j]) / rx2[j] + + (y[i] - ybad[j]) * (y[i] - ybad[j]) / ry2[j] < 1.0) { + location[i] = location[i] | LOCATION_BADPX; + counter++; + break; + } + } + } + cf_verbose(2, "Flagged %d pixels as bad", counter); + + free(xbad); + free(ybad); + free(rxbad); + free(rybad); + + cf_proc_update(header, CF_PRGM_ID, "COMPLETE"); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Done processing"); + return 0; +} diff --git a/src/libcf/cf_screen_burst.c b/src/libcf/cf_screen_burst.c new file mode 100644 index 0000000..f80374e --- /dev/null +++ b/src/libcf/cf_screen_burst.c @@ -0,0 +1,758 @@ +/**************************************************************************** + * Johns Hopkins University + * Center for Astrophysical Sciences + * FUSE + **************************************************************************** + * + * Synopsis: cf_screen_burst(infits, nevents, ptime, x, y, locflags, + * gti, nsec, ttime, sflag, aic_rate, bkgd) + * + * Description: Determines the times for bursts and sets the burst + * flag in the timeline status array so that the busts + * can be removed later. + * + * Arguments: fitsfile infile Pointer to Intermediate Data File + * long nevents Number of photons + * float ptime Time of event + * float *x, *y X and Y positions of the photon + * byte locflags flags on photon location + * (LOC_FLGS column in IDF) + * GTI gti Structure with Good Time Intervals + * long nsec Length of timeline array + * float ttime Timeline array + * byte sflag Status flags in timeline table + * float aic_rate AIC count rate + * short bkgd Count rate for the background + * sample region + * + * Algorithm used: + * + * 1. Generate an array (flgarr) with 1 second intervals that + * contains flags indicating whether that time interval is good + * or not. All elements of this array are originally set to negative + * numbers, indicating bad times. + * 2. Read in the good time intervals from the initial screening + * analysis and set all good time elements in flgarr to positive + * values + * 3. Determine the median count per binned element in the entire time + * sequence (ignoring times with no data) and set all elements with + * a count > 5 times this median value to negative values (indicating + * a burst at that time). + * 4. Do a median filter of the modified time sequence (ignoring the neg + * numbers) and identify all times where the count per bin is greater + * than a specified value or is more than a specified number of + * standard deviations from the median. These points are flagged with + * negative numbers to indicate bursts. The screening parameters used + * are specified in the screening parameter file. + * 5. Iterate time-sequence analysis until no more points are removed. + * 6. Transfer the burst times from the cnt array to flgarr + * 7. Go through all detected photons. If the time of arrival for that + * photon has been flagged as bad in FLGARR then ignore it, + * otherwise copy the information to the output file. + * + * + * Calibration files: + * BCHR_CAL: location of the background sample regions + * SCRN_CAL: burst screening params + * + * Parameter file keywords used to control the burst screening process + * + * MNCNT : minimum enhancement of the background (in counts) needed to + * flag a burst (currently = 5) + * STDRE : minimum number of standard deviations from the local mean + * for a burst to be detected (currently=5) + * NBIN : binning factor (in seconds) for the tiome sequence before + * analysis. (currently=15 seconds) + * NSMED : Interval (in seconds) used in determining the median filter + * (currently=600) + * SRCFRAC : Fraction of the source intensity required for a + * burst to be removed. SCRFRAC=0.01 requires that a burst + * exceed 1% of the integrated source intensity before being + * removed (default 0.001) + * + * Returns: 0 on success + * + * History: 10/29/02 v1.1 RDR Adapted from cf_ttag_burst + * 11/14/02 v1.2 peb Tidied code and made it compatible + * with cf_screen_burst + * 12/09/02 v1.3 RDR - Adjusted procedure for filling + * burst flags in the timeline + * - Corrected error in the procedure + * that tabulates bursts properties. + * - Used LOCATION flags to exclude + * geocoronal emission and photons + * off the active detector. + * 12/20/02 v1.4 rdr changed status flag arrays to + * unsigned char + * 01/24/03 v1.5 rdr corrected problem with high + * count rates + * 03/01/03 v1.6 wvd Correct use of pointer in FITS_read_key + * 05/20/03 v1.7 rdr Add cf_proc_check + * 05/22/03 v1.8 wvd Exit if EXPTIME !> 0. + * Change cf_error_init to stderr. + * Implement cf_verbose throughout. + * 04/06/03 v1.9 rdr Exclude times which have previously + * had a screening bit set + * 09/03/03 v1.10 wvd Delete extraneous print statements + * 09/10/03 v1.11 wvd Change background array to type short + * Set burst flag only when flgarr[i] + * < -1, not 0, to prevent bursts + * from echoing LIMB/SAA/HV flags. + * 09/15/03 v1.12 wvd Use ttime[i] to populate bkgd array. + * Old scheme didn't work. + * 10/06/03 v1.13 wvd Change locflgs to locflags throughout. + * Use bit-wise logic to test sflag array. + * 06/04/04 v1.14 wvd Clean up i/o. + * 02/02/05 v1.15 wvd Read AIC count rate from timeline table + * rather than file header keywords. + * 02/02/05 v1.16 wvd Generate bkgd array for the entire + * exposure, not just good times. + * 08/30/05 v1.17 wvd Ignore photons with arrival times + * greater than MAX_EXPTIME. + * 04/09/06 v1.18 wvd In subroutine median_filter, require + * that nwin >= 1. + * 06/12/06 v1.19 wvd Call cf_verbose rather than + * cf_if_warning. + * + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include "calfuse.h" + +/* + * Function to determine the median value of an array. + * Arguments are the array, + * the number of points in the array (npt) and the maximum count to + * use in the histogram analysis (nmax). The median value is returned. + * + * The analysis uses a histogram approach to determine the median + * value. Negative values of the array have been flagged as bursts + * and should be ignored in determining the median value. If all of + * the points in the array have been flagged, returns zero. + */ + +static int +median(int *array, int npts, int nmax) +{ + int i, ngood=0, *hist, medval; + + /* + * Set up an array to contain the histogram of the data. + */ + hist = (int *) cf_calloc((nmax+1), sizeof(int)); + /* + * Fill the histogram with the data. + * Negative points are not counted. + */ + for (i=0; i< npts; i++) { + int ndx = array[i]; + if (ndx > nmax-1) + ndx = nmax-1; + if (ndx >= 0 ) { + ngood ++; + hist[ndx]++; + } + } + + /* + * Determine the median value. Set the data to 0 if there + * are fewer than 2 points. + */ + if (ngood > 2 ) { + int hnum= (int) ngood/2, atot=0; + i=-1; + while ((atot <= hnum) && (i < nmax) ) + atot += hist[++i]; + medval = (int) i; + } + else + medval = 0; + + free(hist) ; + + return medval; +} + +/* + * Function to construct a median filter for an array: + * array = array for which the median filter is to be constructed + * npts = number of points in the array + * nflt = number of points over which to determine the median value + * medflt = array containing the median filter. + */ + +static void +median_filter(int *array, int npts, int nflt, int *medflt) +{ + int cntmax=0, i, hwidth, nwin, *win, medval, nsam ; + /* + * Determine the maximum value of the array. + */ + for (i = 0; i < npts; i++) + if (array[i] > cntmax) + cntmax=array[i]; + + cf_verbose(3,"Constructing median filter - max cnt = %d",cntmax) ; + + /* + * Determine the properties of the window over which to calculate + * the median values. Make sure that the window is not larger + * than the width of the data. + */ + if (nflt > npts) + hwidth = (int) ( npts/2. ) - 1; + else + hwidth = (int) (0.5 + nflt/2. ); + nwin = (int) 2*hwidth+1; + if (nwin < 1) nwin = 1; + win = (int *) cf_calloc(nwin, sizeof(int)); + /* + * Construct the median filter. + */ + for (i = 0; i < npts; i++) { + int j, nmin, nmax; + /* + * Determine the limits to the sample. + */ + nmin = i - hwidth; + if (nmin < 0) + nmin=0; + nmax = nmin+nwin; + if (nmax > npts-1 ) + nmin = npts-nwin-1; + + /* Fill the sample array */ + nsam=0 ; + for (j=0; j<=2*hwidth; j++) { + int ndx = nmin+j; + if (ndx > npts-1) + ndx = npts-1; + win[j] = array[ndx]; + if (array[ndx] > 0) nsam++ ; + } + + /* Get the median value for the sample array */ + medval = median(win, nwin, cntmax); + + /* + cf_verbose(6,"at point %d, nmin=%d, nmax=%d, nsam=%d, medval=%d", + i, nmin, nmax, nsam, medval) ; + */ + + /* Update the median filter */ + medflt[i] = medval; + } + + free(win) ; + +} + +/* + * Function to take an array marked with the times and intensities of + * the bursts and identify individual bursts events and output these + * to an ASCII file for later analysis. + */ + +static void +tab_burst(int *bursts, int npts, int nbin, int mjd, long tst, char *outfile) +{ + FILE *output; + int i, bflg=-1, bdur=0, bcnts=0, bst=0; + /* + * Go through the bursts array and determine the times and + * properties of the bursts. + */ + output = fopen(outfile, "w"); + + cf_verbose(2, "BURST SUMMARY") ; + for (i=0; i 0 && bflg < 0) { + bflg=1; + bst= i*nbin; + } + if (bursts[i] > 0 && bflg > 0) { + bdur++; + bcnts = bcnts + bursts[i]; + } + if (bursts[i] < 0 && bflg > 0) { + cf_verbose(2, "start=%d, duration=%ld seconds, counts=%d", + bst, bdur*nbin, bcnts) ; + fprintf(output, " %d %ld %d %d \n", + mjd, bst+tst, bdur*nbin, bcnts); + bflg=-1; + bdur=0; + bcnts=0; + } + } + + /* Check to see whether a burst is in progress at the end of the obs */ + if (bflg > 0) { + cf_verbose(2, "start=%d, duration=%ld seconds, counts=%d", + bst, bdur*nbin, bcnts) ; + fprintf(output, " %d %ld %d %d\n", + mjd, bst+tst, bdur*nbin, bcnts); + } + +} + + +int +cf_screen_burst(fitsfile *infits, long nevents, float *ptime, float *x, + float *y, unsigned char *locflags, GTI *gti, long nsec, + float *ttime, unsigned char *sflag, float *aic_rate, + short *bkgd) +{ + char CF_PRGM_ID[] = "cf_screen_burst"; + char CF_VER_NUM[] = "1.19"; + + short ylim[8], k; + int anynull, errflg=0, intnull=0, cflg=-1, nrowbkg=0, ngood; + int npts, nmax, nflt, iflg, numflg, ndxs, ndxe, ndx, ndxb; + int *bcnts, *cnts, *gcnts, *medflt, *flgarr, *bursts, lim_col; + int nflg, niter, mjd , status=0, medval; + long frow=1, felem=1, tst , i, j; + long stdrej, mncnt, nsmed, mnburst, nbin, nflgarr; + float exptime, max_aic_rate, bkgsf, bkgsft, srcfrac, mxtime; + double expstrt; + char burst_tab[FLEN_CARD]; + char expid[FLEN_CARD], progid[FLEN_CARD], targid[FLEN_CARD]; + char scobsid[FLEN_CARD], scrnfile[FLEN_CARD], aperf[FLEN_CARD]; + char det[FLEN_CARD], bchrfile[FLEN_CARD], aper[5]; + fitsfile *scrnfits, *bchrfits; + + /* + * Initialize error checking + */ + cf_error_init(CF_PRGM_ID, CF_VER_NUM, stderr); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Begin Processing"); + if ((errflg = cf_proc_check(infits, CF_PRGM_ID))) return errflg; + + /* + * Read header keywords. + */ + FITS_read_key(infits, TFLOAT, "EXPTIME", &exptime, NULL, &status); + FITS_read_key(infits, TDOUBLE, "EXPSTART", &expstrt, NULL, &status); + FITS_read_key(infits, TSTRING, "PRGRM_ID", progid, NULL, &status); + FITS_read_key(infits, TSTRING, "TARG_ID", targid, NULL, &status); + FITS_read_key(infits, TSTRING, "SCOBS_ID", scobsid, NULL, &status); + FITS_read_key(infits, TSTRING, "EXP_ID", expid, NULL, &status); + FITS_read_key(infits, TSTRING, "DETECTOR", det, NULL, &status); + + /* + * Exit if EXPTIME is 0. + */ + if (exptime < 1) { + cf_verbose(1, "EXPTIME = %f. Exiting.", exptime); + return status; + } + + /* + * Determine the Julian date and start time from expstrt. + */ + mjd = (int) expstrt; + tst = (int) ((expstrt - mjd)*86400.); + det[1] = tolower(det[1]); + + /* Ignore events with arrival times greater than MAX_EXPTIME. */ + i = nevents - 1; + while (ptime[i] > MAX_EXPTIME && i > 0) i--; + nevents = i + 1; + i = nsec - 1; + while (ttime[i] > MAX_EXPTIME && i > 0) i--; + nsec = i + 1; + + /* + * Determine the maximum count rate for the exposure. + * If the count rate is too high, there is the possibility of + * losing counts and of dropouts - Check the count rate and set + * a flag if it is too high. + */ + max_aic_rate = -999.; + for (i = 0; i < nsec; i++) + if (aic_rate[i] > max_aic_rate) max_aic_rate = aic_rate[i]; + cf_verbose(2, "Max AIC count rate = %d", cf_nint(max_aic_rate)); + if(max_aic_rate > 4000) cflg=1; + + /* + * Read the screening parameter file. + */ + FITS_read_key(infits, TSTRING, "SCRN_CAL", scrnfile, NULL, &status); + cf_verbose(3, "Screening parameters from %s\n", scrnfile); + FITS_open_file(&scrnfits, cf_parm_file(scrnfile), READONLY, &status); + FITS_read_key(scrnfits, TLONG, "MNCNT", &mncnt, NULL, &status); + FITS_read_key(scrnfits, TLONG, "STDREJ", &stdrej, NULL, &status); + FITS_read_key(scrnfits, TLONG, "NBIN", &nbin, NULL, &status); + /* + * Set the binning factor to 1 for high count rate data. + */ + if (cflg > 0) { + nbin=1; + cf_verbose(1, "High count-rate observation: using 1 sec time bins") ; + } + FITS_read_key(scrnfits,TLONG,"NSMED",&nsmed, NULL, &status); + /* + * srcfrac=required fraction of the source intensity for a + * burst to be counted, i.e. the burst must exceed this fraction + * before it is deemed to be significant. + */ + FITS_read_key(scrnfits, TFLOAT, "SRCFRAC", &srcfrac, NULL, &status); + FITS_read_key(infits, TSTRING, "APERTURE", aperf, NULL, &status); + FITS_close_file(scrnfits, &status); + + cf_verbose(3, "Screening parameters used:"); + cf_verbose(3, "Minimum count rate = %ld", mncnt); + cf_verbose(3, "Detection criterion (num sigma) = %ld", stdrej); + cf_verbose(3, "Number of seconds to bin the time sequence = %ld", nbin); + cf_verbose(3, "Interval (seconds) used in median filter = %ld", nsmed); + cf_verbose(3, "Fraction of source intensity for burst = %f\n", srcfrac); + /* + * Select the background extraction regions - RFPT implies + * that there is no source, so the entire detector can be used. + */ + strncpy(aper, aperf, 5); + cf_verbose(3, "Aperture designation = %s", aper); + if (strcmp ( aper , "RFPT") == 0 ) { + cf_verbose(3, "APERTURE = RFPT. No source in aperture."); + ylim[0] = 0; + ylim[1] = 1; + ylim[2] = 2; + ylim[3] = 1020; + ylim[4] = 1021; + ylim[5] = 1022; + ylim[6] = 1022; + ylim[7] = 1022; + } + else { + /* + * open the bchr parameter file + */ + FITS_read_key(infits, TSTRING, "BCHR_CAL", bchrfile, NULL, &status); + cf_verbose(3, "BCHR parameter file: %s", bchrfile); + FITS_open_file(&bchrfits, cf_parm_file(bchrfile), READONLY, &status); + + /* Move to the first extension of the BCHR file, which contains + the limits to the background regions */ + FITS_movabs_hdu(bchrfits, 2, NULL, &status); + + /* Get the column number for the data to be extracted */ + FITS_get_colnum(bchrfits, CASEINSEN, aper, &lim_col, &status); + + /* Read the data from the table */ + FITS_read_col(bchrfits, TSHORT, lim_col, frow, felem, 8, &intnull, + ylim, &anynull, &status); + + /* Close the bchr file */ + FITS_close_file(bchrfits, &status); + } + cf_verbose(3, "Y limits of background region: %d-%d, %d-%d, %d-%d\n", + ylim[0], ylim[1], ylim[2], ylim[3], ylim[4], ylim[5]); + /* + * Now get the time sequence and a good time interval flag array. + */ + cf_verbose(3, "nevents = %ld", nevents); + mxtime=ptime[nevents-1]; + nflgarr = cf_nint(mxtime); + npts= (int) mxtime/nbin; + cf_verbose(3, "Number of points in the (binned) time sequence = %d", npts); + cf_verbose(3, "Number of points in the good time flag array = %ld", nflgarr); + /* + * Generate arrays to contain the time sequence in the + * background sample regions (cnts) as well as the entire + * detector (gcnts). Also generate an array to contain only + * the bursts (bursts). + * Array bcnts will contain the background count rate. + */ + bcnts = (int *) cf_calloc(npts, sizeof(int)); + cnts = (int *) cf_calloc(npts, sizeof(int)); + gcnts = (int *) cf_calloc(npts, sizeof(int)); + bursts = (int *) cf_calloc(npts, sizeof(int)); + /* Generate an array to contain the good time flags - this is an array + with 1s time intervals. Each interval is set to a negative number (-1) + if it contains a bad time interval or a positive number (1) if it + contains a good time interval. The contents of this array are used to + screen the photons and to determine the good time intervals */ + flgarr = (int*) cf_calloc(nflgarr, sizeof(int) ); + /* Generate an array with 1s time intervals to contain the day/night + information - this will be 1 for night and 0 for day */ + + /* Initially flag all of the points with a negative number. + The good time intervals will be determined later */ + for (i=0; intimes; i++) { + ndxs= (int) gti->start[i]/nbin; + if (ndxs < 0 ) ndxs = 0 ; + ndxe = (int) (0.5 + gti->stop[i]/nbin); + if (ndxe > npts-1) ndxe = npts-1; + for (j=ndxs; j<= ndxe; j++) { + ngood++; + cnts[j]=0; + } + } + cf_verbose(2, "Number of good time points = %d\n", ngood); + + /* Set the good time flags array to a positive value for all good + time points */ + + for (i=0; i < gti->ntimes; i++) { + ndxs= (int) gti->start[i]; + if (ndxs < 0) ndxs = 0 ; + ndxe = (int) gti->stop[i]; + if (ndxe > nflgarr-1) ndxe=nflgarr-1; + for (j=ndxs; j<= ndxe; j++) + flgarr[j]=1; + } + + /* Check the timeline-table screening flag and mark all times that have + a screening bit set (except for day/night) */ + for (i=0; i nflgarr-1) ndx = nflgarr-1; + if( ndx < 0) ndx = 0 ; + ndxb = (int) (0.5 + (float) ndx/ (float) nbin) ; + if(ndxb > npts-1) ndxb = npts-1 ; + if (ndxb < 0) ndxb=0 ; + if (sflag[i] & ~TEMPORAL_DAY) { + flgarr[ndx] = -1 ; + cnts[ndxb] = -10 ; + } + } + + /* Generate the time sequence for the total counts from the detector. + Use only the active area and ignore geocoronal emission. */ + + for (i=0; i < nevents; i+=1) + if( (locflags[i] & LOCATION_SHLD) == 0 && + (locflags[i] & LOCATION_AIR) == 0 ) { + int ndx = (int) ptime[i]/nbin; + if (ndx > npts-1) + ndx=npts-1; + if (ndx < 0) + ndx=0; + gcnts[ndx] += 1; + } + + /* Determine the number of rows in the background sample region */ + for (k=0; k < 3; k++) + nrowbkg += ylim[2*k+1] - ylim[2*k]; + /* + * Determine the scaling factor needed to convert the measured + * counts in the background regions to an estimate of the + * background counts over the active aperture. + */ + bkgsf= (float) ylim[6]/nrowbkg; + bkgsft = (float) ylim[7]/nrowbkg; + + cf_verbose(2, "Rows in target aperture = %d", ylim[6]); + cf_verbose(2, "Rows on the detector = %d", ylim[7]); + cf_verbose(2, "Rows in background region = %d", nrowbkg); + cf_verbose(2, "Scale factor to aperture = %f ", bkgsf); + cf_verbose(2, "Scale factor to entire detector = %f", bkgsft); + + /* Generate the time sequence using only the counts from the three + selected background regions - ignore geocoronal lines and times + that have been flagged as bad (with negative count values) */ + for (k=0; k<3; k++) { + short ylow=ylim[2*k]; + short yhigh=ylim[2*k+1]; + for (i=0; i < nevents; i+=1) { + if( (locflags[i] & LOCATION_SHLD) == 0 && + (locflags[i] & LOCATION_AIR) == 0 && + (y[i] > ylow) && (y[i] < yhigh) ) { + int ndx = (int) ptime[i]/nbin; + if (ndx > npts-1) + ndx=npts-1; + if (ndx < 0) + ndx=0; + if (cnts[ndx] >= 0) cnts[ndx] += 1; + bcnts[ndx] ++; + } + } + } + + /* Fill background count rate array with cnts array, and divide by nbin + to give count rate */ +/* THIS SCHEME WORKS ONLY IF THERE ARE NO TIME BREAKS IN THE TIMELINE + * TABLE. SINCE TIME BREAKS ARE COMMON, MUST USE TTIME ARRAY TO MAP + * CNTS ARRAY TO BKGD ARRAY. WVD 09/15/03 + * for (i=0; i nsec-1) + * ndxe=nsec-1; + * for (j=ndxs;j nflgarr-1) + ndx = nflgarr-1; +/* if (cnts[ndx] > 0.) + bkgd[i] = (short) ((float) cnts[ndx] / nbin + 0.5); + else + bkgd[i] = 0; +*/ + bkgd[i] = bcnts[ndx] / nbin; + } + free (bcnts); + + /* Remove the background counts (scaled to the entire detector) from the + measured gross count rate */ + for (i=0; i < npts; i++) if (cnts[i] > 0) { + gcnts[i] = gcnts[i] - bkgsft*cnts[i]; + if (gcnts[i] < 0) + gcnts[i] = 0; + } + + /* Check for zeros in the count array for high count rate data - these + indicate dropouts. If one is found, flag it with a negative number so + that the program will ignore it in future analysis */ + numflg=0; + if (cflg > 0) { + for (i=0; i < npts; i++) { + if (cnts[i] <= 0.1 ) { + numflg += 1; + cnts[i]=-10; + } + } + } + cf_verbose(2, "Number of dropouts found = %d", numflg); + + /* Determine the median value of the array */ + nmax=2000; + medval = median(cnts, npts, nmax); + cf_verbose(2, "Median value of the entire original array = %d ", medval); + + /* Screen the time series for very large count rates (> 3 x median) */ + cf_verbose(2, "Searching for large bursts ") ; + for ( i=0; i 4*medval) { + cf_verbose(2,"point rej: time=%d, cnts=%d, 4*medval=%d ", + i*nbin, cnts[i], 4*medval) ; + bursts[i] = cnts[i]-medval; + cnts[i] = -100; + } + + /* Do a median filter on the pre-filtered array */ + + /* Generate the array to contain the median filter */ + medflt = (int *) cf_calloc(npts, sizeof(int) ); + + /* + * Now specify the parameters of the filter - + * nsmed = number of seconds over which to determine median values + * nflt = number of points in the cnts array over which to + * determine the median value + */ + nflt = nsmed / nbin; + niter=0; + + cf_verbose(3,"Searching for small bursts - nflt = %d", nflt) ; + + do { + median_filter(cnts, npts, nflt, medflt); + + /* Throw out all points which are more than (stdrej) standard + deviations above the median. Also require that the counts exceed + a certain minimum value. */ + nflg=0; + mnburst=mncnt*nbin; + for (i=0; i mnburst) && + (dcnt > stdrej*sqrt((double) cnts[i])) && + (dcnt*bkgsf > srcfrac*gcnts[i]) ) { + nflg++; + cf_verbose(2, "point rej: time=%ld, cnts=%d, medflt=%d, " + "dif=%d, gcnts= %d", + i*nbin, cnts[i], medflt[i], dcnt, gcnts[i]); + cnts[i] = -100; + bursts[i] = dcnt; + } + } + niter++; + cf_verbose(3,"After iteration %d, we found %d times affected by bursts", + niter, nflg) ; + /* Iterate the median filter if any additional points have + * been modified*/ + } while(nflg > 0 && niter < 10); + + /* Print out the results of the screening + cf_verbose(5, " "); + for (i=0; i nflgarr-nbin-2) + ndxs=nflgarr-nbin-2; + ndxe = ndxs + nbin - 1; + for (j=ndxs; j<=ndxe; j++) + flgarr[j] = -10; + } + } + + /* tabulate the burst times */ + sprintf(burst_tab, "%4s%2s%2s%3s%2s_bursts.dat", progid, targid, scobsid, expid, det); + tab_burst(bursts, npts, nbin, mjd, tst, burst_tab); + cf_verbose(3, "Burst properties written to file: %s", burst_tab); + + /* Check the last 2*nbin elements of flgarr. If any of these are set as + bad, then set all the end points as bad. The binned count time sequence + will not sample the end of the ovarall time sequence if there is not an + integral number of bins present. We also do not need the last bin if the + second-to-last is bad. */ + + i=nflgarr-2*nbin; + iflg=10; + do{ + if (flgarr[i] < -1) { /* 09/12/03 - wvd - Change from 0 */ + for (j=i; j 0 && i < nflgarr); + + /* set the timeline status flag (sflag - TEMPORAL_BRST) for all + times containing bursts */ + for (i=0; i nflgarr-1) + ndx = nflgarr-1; + if (flgarr[ndx] < -1) /* 09/12/03 - wvd - Change from 0 */ + sflag[i] = sflag[i] | TEMPORAL_BRST; + } + /* deallocate storage space */ + free(cnts) ; + free(gcnts) ; + free(flgarr) ; + free(medflt) ; + free(bursts) ; + + /* Enter a time stamp into the log */ + cf_proc_update(infits, CF_PRGM_ID, "COMPLETE"); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Finished processing"); + + return (status); +} diff --git a/src/libcf/cf_screen_high_voltage.c b/src/libcf/cf_screen_high_voltage.c new file mode 100644 index 0000000..57a9716 --- /dev/null +++ b/src/libcf/cf_screen_high_voltage.c @@ -0,0 +1,146 @@ +/***************************************************************************** + * Johns Hopkins University + * Center For Astrophysical Sciences + * FUSE + ***************************************************************************** + * + * Synopsis: cf_screen_high_voltage(fitsfile *infits, long nseconds, + * unsigned char *timeline_status, short *timeline_hv); + * + * Description: Set the screening bit if detector voltage is low. + * + * Arguments: fitsfile *infits Input FITS file pointer + * long nseconds Number of points in the timeline table + * unsigned char *timeline_status The status flag array + * short *timeline_hv The high voltage array + * + * Calls: + * + * Returns: 0 on success + * + * History: 10/23/02 1.1 jch Initial coding + * 12/20/02 1.3 jch Make sure the flags are "unsigned" char + * 01/24/03 1.4 rdr Lower the voltage threshold required + * to flag a time to 95% of the full + * voltage + * 02/11/03 1.6 jch Skip HV which is negative + * 05/20/03 1.7 rdr Add call to cf_proc_check + * 05/22/03 1.8 wvd Implement cf_verbose + * 06/11/03 1.9 wvd Change HV array to type short. + * 06/13/03 1.10 wvd Change calfusettag.h to calfuse.h + * 09/10/03 1.11 wvd Return errflg from cf_proc_check. + * 07/21/04 1.12 wvd Delete unused variable volt_cor. + * 02/17/05 1.13 wvd Place parentheses around assignment + * used as truth value. + * 03/18/05 1.14 wvd HV can be 0, so test for HV > -1 + * 03/24/05 1.15 wvd Read HVGOODLM and HVBADLIM from + * VOLT_CAL file. If HV/FULLV drops + * below HVGOODLM, issue warning. + * If it falls below HVBADLM, set + * TEMPORAL_HV flag. + * 06/22/06 1.16 wvd Don't set EXP_STAT keyword. + * + ****************************************************************************/ + +#include +#include +#include "calfuse.h" + +int +cf_screen_high_voltage(fitsfile *infits, long nseconds, + unsigned char *timeline_status, short *timeline_hv) +{ + char CF_PRGM_ID[] = "cf_screen_high_voltage"; + char CF_VER_NUM[] = "1.16"; + + char file_name[FLEN_VALUE], mjd_str[FLEN_VALUE], full_str[FLEN_VALUE]; + char datestr[FLEN_VALUE], comment[FLEN_COMMENT], instmode[FLEN_VALUE]; + int errflg=0, status=0, timeref, hvflag=FALSE, n, fullv; + long i; + float expstart, hvfrac, hvgood, hvbad, mjdv; + fitsfile *scrnfits; + + cf_error_init(CF_PRGM_ID, CF_VER_NUM, stderr); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Begin Processing"); + if ((errflg = cf_proc_check(infits, CF_PRGM_ID))) return errflg; + + /* Read exposure start time and instrument mode. */ + FITS_read_key(infits, TFLOAT, "EXPSTART", &expstart, NULL, &status); + FITS_read_key(infits, TSTRING, "INSTMODE", instmode, NULL, &status); + /* + * Open the high-voltage calibration file. + */ + FITS_read_key(infits, TSTRING, "VOLT_CAL", file_name, NULL, &status); + FITS_open_file(&scrnfits, cf_cal_file(file_name), READONLY, &status); + /* + * Read the limits of the good and questionable voltage regimes. + */ + FITS_read_key(scrnfits, TFLOAT, "HVGOODLM", &hvgood, NULL, &status); + FITS_read_key(scrnfits, TFLOAT, "HVBADLIM", &hvbad, NULL, &status); + /* + * Read full-voltage level in use at time of observation. + */ + n = 0; + do { + n++; + sprintf(mjd_str, "MJD%d", n); + FITS_read_key(scrnfits, TFLOAT, mjd_str, &mjdv, NULL, &status); + } while (expstart > mjdv); + n--; + + sprintf(full_str, "FULL%d", n); + FITS_read_key(scrnfits, TINT, full_str, &fullv, NULL, &status); + FITS_close_file(scrnfits, &status); + + /* + * Check for low values of the detector voltage. + * Set the high voltage bit if timeline_hv/fullv < hvbad. + */ + cf_verbose(2, "Threshold voltage = %d", cf_nint(hvbad * fullv)) ; + + for (i = 0; i < nseconds; i++) if (timeline_hv[i] > -1) { + hvfrac = timeline_hv[i] / (float) fullv; + if (hvfrac < hvgood) { + if (hvfrac < hvbad) timeline_status[i] |= TEMPORAL_HV; + else hvflag = TRUE; + } + } + + /* + * If the detector voltage ever falls between the good and bad + * levels, issue a stern warning to the user. + */ + if (hvflag) { + /* Write warning to trailer file. */ + if (!strncmp(instmode, "HIST", 4)) + cf_if_warning("Detector voltage is < 90%% of optimal value. " + "Check photometry and wavelength scale."); + else + cf_if_warning("Detector voltage is < 90%% of optimal value. " + "Check pulse-height distribution."); + + /* Write warning to IDF file header. */ + FITS_write_comment(infits, " ", &status); + FITS_write_comment(infits, + "Detector voltage is less than 90%% of optimal value.", &status); + if (!strncmp(instmode, "HIST", 4)) { + FITS_write_comment(infits, + "Carefully examine these data for photometric errors", &status); + FITS_write_comment(infits, "and walk effects.", &status); + } + else { + FITS_write_comment(infits, + "Carefully examine the pulse height distribution of photons", &status); + FITS_write_comment(infits, + "in the target aperture before accepting these data.", &status); + } + fits_get_system_time(datestr, &timeref, &status); + sprintf(comment, "CalFUSE v%s %.10s", CALFUSE_VERSION, datestr); + FITS_write_comment(infits, comment, &status); + FITS_write_comment(infits, " ", &status); + } + + cf_proc_update(infits, CF_PRGM_ID, "COMPLETE"); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Done processing"); + return status; +} diff --git a/src/libcf/cf_screen_jitter.c b/src/libcf/cf_screen_jitter.c new file mode 100644 index 0000000..68327a0 --- /dev/null +++ b/src/libcf/cf_screen_jitter.c @@ -0,0 +1,246 @@ +/***************************************************************************** + * Johns Hopkins University + * Center for Astrophysical Sciences + * FUSE + ***************************************************************************** + * + * Synopsis: cf_screen_jitter (infile, nsec, ttime, status_flag) + * + * Description: Flag times when target is out of the aperture or pointing + * is known to be bad. Read the minimum trustworthy TRKFLG + * value and aperture limits from the parameter file. + * + * Key to new TRKFLG values: + * 5 = dx, dy from known FPDs and q_cmd from telemetry + * 4 = good dx, dy from ACS q_est and q_cmd from telemetry + * 3 = maybe good dx, dy from ACS q_est + * 2 = dx, dy from known FPDs, q_cmd from FITS header coordinates + * 1 = dx, dy from ACS q_est, q_cmd from FITS header coordinates + * 0 = no pointing information (missing telemetry) + * -1 = Pointing is assumed to be bad (never achieved known track) + * + * Arguments: fitsfile infile Pointer to the IDF + * long nsec Number of seconds in the timeline + * long *ttime time (sec) of each point in the timeline + * unsigned char *status_flag Timeline status flags + * + * Returns: 0 upon success + * + * History: 11/29/05 v1.1 wvd Adapted from cf_satellite_jitter + * 03/28/06 1.2 wvd Test both dx and dy. + * 05/09/06 1.3 wvd Apply jitter screening to RFPT obs. + * 06/12/06 1.4 wvd Call cf_verbose when jitter file not + * found. + * 08/21/06 1.5 wvd Use EXPSTART in jitter and data + * headers to correct jitter time array. + * 08/25/06 1.6 wvd Change meaning of TRKFLG values. + * TRKFLG = 3 is only used internally. + * 11/06/06 1.7 wvd Change meaning of TRKFLG values. + * Read minimum TRKFLG value and + * aperture limits from parmfile. + * Require jitter file version >= 3.0. + * Don't screen moving targets. + * Bail out only if JIT_STAT = 1. + * 12/29/06 1.8 wvd Exit if JIT_VERS < 3.0. + * 03/23/07 1.9 wvd Store offset between the jitter and + * data values of EXPSTART in variable + * time_diff. + * 04/07/07 1.10 wvd Clean up compiler warnings. + * 08/16/07 1.11 wvd Don't apply jitter correction to + * observations taken after the + * spacecraft lost pointing control. + * 07/25/08 1.12 wvd Use EXP_STAT keyword, rather than + * file name, to check for bright-earth + * or airglow observations. + * 11/21/08 1.13 wvd Don't apply jitter correction to + * ERO observations of Jupiter. + * + ****************************************************************************/ + +#include +#include +#include +#include +#include "calfuse.h" + +#define JIT_VERS_MIN 3.0 +#define BAD_TRKFLG -1 +#define LAST_MJD 54300. + +int +cf_screen_jitter(fitsfile *infits, long nsec, float *ttime, + unsigned char *status_flag) +{ + char CF_PRGM_ID[] = "cf_screen_jitter"; + char CF_VER_NUM[] = "1.13"; + + char jitr_cal[FLEN_VALUE], parmfile[FLEN_VALUE]; + char comment[FLEN_COMMENT], hkexists[FLEN_VALUE], jit_vers[FLEN_VALUE]; + char mov_targ[FLEN_VALUE], program[FLEN_VALUE]; + int errflg=0, status=0, expstat, jitter_status, hdutype; + long j, k, njitr, *time_jit, time_diff; + short *trkflg, trkflg_min; + double data_expstart, jitr_expstart; + float *dx_jit, *dy_jit, dx_max, dy_max; + fitsfile *jitfits, *parmfits; + + /* Initialize error checking */ + cf_error_init(CF_PRGM_ID, CF_VER_NUM, stderr); + + /* Enter a time stamp into the log */ + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Begin Processing"); + + /* Read exposure start time from IDF header */ + FITS_read_key(infits, TDOUBLE, "EXPSTART", &data_expstart, NULL, &status); + + /* Check whether program is appropriate for this data set. */ + if ((errflg = cf_proc_check(infits, CF_PRGM_ID))) return errflg; + + /* Don't apply jitter screening to bright-earth or airglow observations. */ + FITS_read_key(infits, TINT, "EXP_STAT", &expstat, NULL, &status); + if (expstat == (int) TEMPORAL_LIMB) { + cf_verbose(1, "Bright-earth or airglow observation. ", + "No jitter correction."); + cf_proc_update(infits, CF_PRGM_ID, "SKIPPED"); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Finished processing"); + return 0; + } + + /* Don't apply jitter screening to moving targets. */ + FITS_read_key(infits, TSTRING, "MOV_TARG", mov_targ, NULL, &status); + if (!strncmp(mov_targ, "M", 1)) { + cf_verbose(1, "Moving-target observation. No jitter correction."); + cf_proc_update(infits, CF_PRGM_ID, "SKIPPED"); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Finished processing"); + return 0; + } + + /* Don't apply jitter screening to ERO observations of Jupiter. */ + FITS_read_key(infits, TSTRING, "PRGRM_ID", program, NULL, &status); + if (!strncmp(program, "X006", 4)) { + cf_verbose(1, "Moving-target observation. No jitter correction."); + cf_proc_update(infits, CF_PRGM_ID, "SKIPPED"); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Finished processing"); + return 0; + } + + /* Don't apply jitter screening after pointing control is lost. */ + if (data_expstart > LAST_MJD) { + cf_verbose(1, "No pointing control. No jitter correction."); + cf_proc_update(infits, CF_PRGM_ID, "SKIPPED"); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Finished processing"); + return 0; + } + + /* Check HKEXISTS before looking for jitter file. */ + FITS_read_key(infits, TSTRING, "HKEXISTS", hkexists, NULL, &status); + if(!strncasecmp(hkexists, "N", 1) || !strncasecmp(hkexists, "n", 1)) { + cf_verbose(1, "HKEXISTS = %s. No jitter correction.", hkexists); + cf_proc_update(infits, CF_PRGM_ID, "SKIPPED"); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Finished processing"); + return 0; + } + + /* Try to open the jitter file. */ + FITS_read_key(infits, TSTRING, "JITR_CAL", jitr_cal, NULL, &status); + fits_open_file(&jitfits, jitr_cal, READONLY, &status); + + /* If the jitter file is not found, try a lower-case filename. */ + if (status != 0) { + status = 0; + jitr_cal[0] = (char) tolower(jitr_cal[0]); + fits_open_file(&jitfits, jitr_cal, READONLY, &status); + } + + /* If the jitter file is still not found, exit the program */ + if (status != 0) { + cf_verbose(1, "Jitter file not found. No jitter correction."); + cf_proc_update(infits, CF_PRGM_ID, "SKIPPED"); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Finished processing"); + return 0; + } + cf_verbose(3, "Jitter calibration file = %s", jitr_cal); + + /* Check status keyword in jitter file. Exit if missing or non-zero. */ + fits_read_key(jitfits, TINT, "JIT_STAT", &jitter_status, comment, &status); + if (status != 0) { + status = 0; + cf_verbose(1, "Keyword JIT_STAT not found. No jitter correction."); + cf_proc_update(infits, CF_PRGM_ID, "SKIPPED"); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Finished processing"); + return 0; + } + if (jitter_status == 1) { + cf_verbose(1, "Keyword JIT_STAT = %d. No jitter correction.", + jitter_status) ; + cf_proc_update(infits, CF_PRGM_ID, "SKIPPED"); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Finished processing"); + return 0; + } + + /* Read exposure start time from jitter file header */ + FITS_read_key(jitfits, TDOUBLE, "EXPSTART", &jitr_expstart, NULL, &status); + + /* Check JIT_VERS keyword. Exit if missing or value too low. */ + fits_read_key(jitfits, TSTRING, "JIT_VERS", jit_vers, NULL, &status); + if (status != 0 || atof(jit_vers) < JIT_VERS_MIN) { + status = 0; + cf_verbose(1, "Jitter file format is out of date. No jitter correction."); + cf_proc_update(infits, CF_PRGM_ID, "SKIPPED"); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Finished processing"); + return 0; + } + + /* Read the jitter file. */ + FITS_movabs_hdu(jitfits, 2, &hdutype, &status); + njitr=cf_read_col(jitfits, TLONG, "TIME", (void **) &time_jit); + njitr=cf_read_col(jitfits, TFLOAT, "DX", (void **) &dx_jit); + njitr=cf_read_col(jitfits, TFLOAT, "DY", (void **) &dy_jit); + njitr=cf_read_col(jitfits, TSHORT, "TRKFLG", (void **) &trkflg); + FITS_close_file(jitfits, &status); + + /* Correct for difference in data and jitter EXPSTART times */ + time_diff = cf_nlong((data_expstart - jitr_expstart) * 86400.); + cf_verbose(2, "Offset between IDF and jitter EXPSTART values: %d sec", + time_diff); + for (j=0; j< njitr; j++) time_jit[j] -= time_diff; + + /* Read minimum TRKFLG value and aperture boundaries from PARM_CAL file */ + FITS_read_key(infits, TSTRING, "PARM_CAL", parmfile, NULL, &status); + FITS_open_file(&parmfits, cf_parm_file(parmfile), READONLY, &status); + FITS_read_key(parmfits, TSHORT, "TRKFLG", &trkflg_min, NULL, &status); + FITS_read_key(parmfits, TFLOAT, "DX_MAX", &dx_max, NULL, &status); + FITS_read_key(parmfits, TFLOAT, "DY_MAX", &dy_max, NULL, &status); + FITS_close_file(parmfits, &status); + + /* Reject times when tracking is good, but target is out of aperture. */ + for (j=0; j< njitr; j++) { + if (trkflg[j] >= trkflg_min && + (dx_jit[j] < -dx_max || dx_jit[j] > dx_max || + dy_jit[j] < -dy_max || dy_jit[j] > dy_max)) { + trkflg[j] = BAD_TRKFLG; + } + } + + /* + * Map times in the jitter file to times in the timeline table. + * If trkflg[j] = BAD_TRKFLG, set the jitter flag in the timeline + * status array. + */ + for (j=k=0; k < nsec; k++) { + while ((float) time_jit[j+1] < ttime[k] && j+1 < njitr) j++; + if (trkflg[j] == BAD_TRKFLG) { + status_flag[k] |= TEMPORAL_JITR; + } + } + + /* Deallocate storage space */ + free(time_jit); + free(dy_jit); + free(trkflg); + + cf_proc_update(infits, CF_PRGM_ID, "COMPLETE"); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Finished processing"); + + return (status); +} diff --git a/src/libcf/cf_screen_limb_angle.c b/src/libcf/cf_screen_limb_angle.c new file mode 100644 index 0000000..5e2f54b --- /dev/null +++ b/src/libcf/cf_screen_limb_angle.c @@ -0,0 +1,87 @@ +/***************************************************************************** + * Johns Hopkins University + * Center For Astrophysical Sciences + * FUSE + ***************************************************************************** + * + * Synopsis: cf_screen_limb_angle(fitsfile *infits, long nseconds, + * unsigned char *timeline_status, + * float *timeline_limb); + * + * Description: Set the screening bit due to limb angle constraint. + * + * Arguments: fitsfile *infits Input FITS file pointer + * long nseconds Number of points in the timeline table + * unsigned char *timeline_status The status flag array + * float *timeline_limb The limb angle distance array + * + * Calls: + * + * Returns: 0 on success + * + * History: 10/21/02 1.1 jch Initial coding + * 12/20/02 1.3 jch Make sure the flags are unsigned char + * 05/20/03 1.4 rdr Added call to cf_proc_check + * 09/10/03 1.5 wvd Move test of LIMB_SCR to cf_fuv_init. + * 07/21/04 1.7 wvd Delete unused variable limb_cor. + * 02/17/05 1.8 wvd Place parentheses around assignment + * used as truth value. + * 03/30/05 1.9 wvd Write BRITLIMB and DARKLIMB keywords + * to IDF file header. + * + ****************************************************************************/ + +#include +#include +#include "calfuse.h" + +int +cf_screen_limb_angle(fitsfile *infits, long nseconds, + unsigned char *timeline_status, float *timeline_limb) +{ + char CF_PRGM_ID[] = "cf_screen_limb_angle"; + char CF_VER_NUM[] = "1.9"; + + int errflg=0, status=0; + long i; + char file_name[FLEN_VALUE]; + double angle, britlimb, darklimb; + fitsfile *scrnfits; + + cf_error_init(CF_PRGM_ID, CF_VER_NUM, stderr); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Begin Processing"); + + if ((errflg = cf_proc_check(infits, CF_PRGM_ID))) return errflg; + + /* + * Open the screening parameters file and read the parameters. + */ + FITS_read_key(infits, TSTRING, "SCRN_CAL", file_name, NULL, &status); + FITS_open_file(&scrnfits, cf_parm_file(file_name), READONLY, &status); + + FITS_read_key(scrnfits, TDOUBLE, "BRITLIMB", &britlimb, NULL, &status); + FITS_read_key(scrnfits, TDOUBLE, "DARKLIMB", &darklimb, NULL, &status); + /* + * Write BRITLIMB and DARKLIMB keywords to IDF file header. + */ + FITS_update_key(infits, TDOUBLE, "BRITLIMB", &britlimb, NULL, &status); + FITS_update_key(infits, TDOUBLE, "DARKLIMB", &darklimb, NULL, &status); + /* + * If the limb angle is less than the limit, set the limb-angle bit. + * Use day or night limit as appropriate. + */ + for (i = 0; i < nseconds; i++) { + angle = darklimb; + if ((timeline_status[i] & TEMPORAL_DAY) == TEMPORAL_DAY) { + angle = britlimb; + } + if (timeline_limb[i] < angle) { + timeline_status[i] |= TEMPORAL_LIMB; + } + } + FITS_close_file(scrnfits, &status); + + cf_proc_update(infits, CF_PRGM_ID, "COMPLETE"); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Done processing"); + return status; +} diff --git a/src/libcf/cf_screen_pulse_height.c b/src/libcf/cf_screen_pulse_height.c new file mode 100644 index 0000000..3b2c43e --- /dev/null +++ b/src/libcf/cf_screen_pulse_height.c @@ -0,0 +1,79 @@ +/***************************************************************************** + * Johns Hopkins University + * Center For Astrophysical Sciences + * FUSE + ***************************************************************************** + * + * Synopsis: cf_screen_pulse_height(fitsfile *infits, long nevents, + * unsigned char *photon_ph, + * unsigned char *photon_locflag); + * + * Description: Set the screening bit according to PHA limits. + * + * Arguments: fitfile *infits Input FITS file pointer + * long nevents Number of points in the photon list + * unsigned char *photon_ph The photon pulse height array + * unsigned char *photon_locflag The photon location array + * + * Returns: 0 on success + * + * History: 11/01/02 1.1 jch Initial coding + * 12/20/02 1.3 jch Make sure the flags are "unsigned" char + * 02/14/03 1.4 rdr Update phalow and phahigh keywords + * in the IDF + * 05/20/03 1.5 rdr Add call to cf_proc_check + * 09/10/03 1.6 wvd Write NBADPHA as type LONG. + * 10/02/03 1.7 wvd Move PHA bit from TEMPORAL to + * LOCATION flags. + * 05/04/04 1.9 bjg Cosmetic change to prevent + * compiler warning with gcc -Wall + * + ****************************************************************************/ + +#include +#include +#include "calfuse.h" + +int +cf_screen_pulse_height(fitsfile *infits, long nevents, unsigned char *photon_ph, + unsigned char *photon_locflag) +{ + char CF_PRGM_ID[] = "cf_screen_pulse_height"; + char CF_VER_NUM[] = "1.9"; + + char scrnfile[FLEN_VALUE]; + unsigned char phalow, phahigh; + int errflg=0, status=0; + long i, nbadpha=0; + fitsfile *scrnfits; + + cf_error_init(CF_PRGM_ID, CF_VER_NUM, stderr); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Begin Processing"); + + if ((errflg = cf_proc_check(infits, CF_PRGM_ID))) return errflg; + + /* + * Open the screening parameters file and read the parameters. + */ + FITS_read_key(infits, TSTRING, "SCRN_CAL", scrnfile, NULL, &status); + FITS_open_file(&scrnfits, cf_parm_file(scrnfile), READONLY, &status); + FITS_read_key(scrnfits, TBYTE, "PHALOW", &phalow, NULL, &status); + FITS_read_key(scrnfits, TBYTE, "PHAHIGH", &phahigh, NULL, &status); + FITS_close_file(scrnfits, &status); + /* + * Set the pulse-height bit if pulse height is outside limits. + */ + for (i = 0; i < nevents; i++) { + if (photon_ph[i] < phalow || photon_ph[i] > phahigh) { + photon_locflag[i] |= LOCATION_PHA; + nbadpha++; + } + } + FITS_update_key(infits, TLONG, "NBADPHA", &nbadpha, NULL, &status); + FITS_update_key(infits, TBYTE, "PHALOW", &phalow, NULL, &status); + FITS_update_key(infits, TBYTE, "PHAHIGH", &phahigh, NULL, &status); + + cf_proc_update(infits, CF_PRGM_ID, "COMPLETE"); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Done processing"); + return status; +} diff --git a/src/libcf/cf_screen_saa.c b/src/libcf/cf_screen_saa.c new file mode 100644 index 0000000..c79dc6e --- /dev/null +++ b/src/libcf/cf_screen_saa.c @@ -0,0 +1,83 @@ +/***************************************************************************** + * Johns Hopkins University + * Center For Astrophysical Sciences + * FUSE + ***************************************************************************** + * + * Synopsis: cf_screen_saa(fitsfile *infits, long nseconds, + * unsigned char *timeline_status, + * float *timeline_long, float *timeline_lat); + * + * Description: Set the screening bit due to SAA boundary. + * + * Arguments: fitsfile *infits Input FITS file pointer + * long nseconds Number of points in the timeline table + * unsigned char *timeline_status The status flag array + * float *timeline_long The longitude array + * float *timeline_lat The latitude array + * + * Calls: saa + * + * Returns: 0 on success + * + * History: 10/29/02 1.1 jch Initial coding + * 12/20/02 1.3 jch Include reading SAA table here + * 12/20/02 1.4 wvd Delete call to calfuse.h + * 05/20/03 1.5 rdr Add call to cf_proc_check + * 08/28/03 1.6 bjg New definition of structure saareg + * 09/02/03 1.7 wvd Change calfusettag.h to calfuse.h + * 09/10/03 1.8 wvd Tidy up code. + * 02/17/05 1.9 wvd Place parentheses around assignment + * used as truth value. + * + ****************************************************************************/ + +#include + +#include "calfuse.h" + +int +cf_screen_saa(fitsfile *infits, long nseconds, unsigned char *timeline_status, + float *timeline_long, float *timeline_lat) +{ + char CF_PRGM_ID[] = "cf_screen_saa"; + char CF_VER_NUM[] = "1.9"; + + char saa_cal[FLEN_VALUE]; + int errflg=0, status=0, hdutype; + long i; + saareg saa_bounds; + fitsfile *saafits; + + cf_error_init(CF_PRGM_ID, CF_VER_NUM, stderr); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Begin Processing"); + if ((errflg = cf_proc_check(infits, CF_PRGM_ID))) return errflg; + + /* + * Read SAA boundaries from the specified calibration file. + */ + FITS_read_key(infits, TSTRING, "SAAC_CAL", saa_cal, NULL, &status); + FITS_open_file(&saafits, cf_cal_file(saa_cal), READONLY, &status); + FITS_movabs_hdu(saafits, 2, &hdutype, &status); + + saa_bounds.n_points = + cf_read_col(saafits, TFLOAT, "LATITUDE", (void **) &(saa_bounds.lat)); + (void) cf_read_col(saafits, TFLOAT, "LONGITUDE", (void **) &(saa_bounds.lon)); + + fits_close_file(saafits, &status); + + /* + * Set the SAA boundary bit if in SAA + */ + for (i = 0; i < nseconds; i++) { + if (saa(&saa_bounds, (double)timeline_long[i], (double)timeline_lat[i])) { + timeline_status[i] |= TEMPORAL_SAA; + } + } + free(saa_bounds.lon); + free(saa_bounds.lat); + + cf_proc_update(infits, CF_PRGM_ID, "COMPLETE"); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Done processing"); + return status; +} diff --git a/src/libcf/cf_set_good_time_intervals.c b/src/libcf/cf_set_good_time_intervals.c new file mode 100644 index 0000000..2ed0d54 --- /dev/null +++ b/src/libcf/cf_set_good_time_intervals.c @@ -0,0 +1,157 @@ +/***************************************************************************** + * Johns Hopkins University + * Center For Astrophysical Sciences + * FUSE + ***************************************************************************** + * + * Synopsis: cf_set_good_time_intervals(fitsfile *infits, long nseconds, + * float *timeline_time, + * unsigned char *timeline_status, GTI *gti); + * + * Description: Compute the new good time intervals based on the timeline + * status flag. + * + * Arguments: fitsfile *infits Input FITS file pointer + * long nseconds Length of timeline table + * float *timeline_time Time array of timeline list + * unsigned char *timeline_status Status array of timeline list + * GIT *gti Good time interval(s) + * + * Calls: + * + * Returns: 0 on success + * -1 on error + * + * History: 11/01/02 1.1 jch Initial coding + * 12/20/02 1.3 jch Make sure that flags are unsigned char + * 05/09/03 1.4 wvd Include D/N screening in GTI's. + * Calculate EXPTIME as SUM (GTI's). + * Update header keyword EXPTIME. + * 05/20/03 1.5 rdr Add call to cf_proc_check + * 05/29/03 1.6 wvd Allow lower-case value of DAYNIGHT. + * Correct bug in calculation of gti.stop + * If in HIST mode, ignore LIMB, SAA, + * and BRST flags. + * 09/10/03 1.7 wvd Change calfusettag.h to calfuse.h + * 10/13/03 1.8 wvd Modify for new timeline table format. + * No time skips. + * 04/20/04 1.9 bjg Remove unused variables + * 12/01/04 1.10 bjg Set gti start and stop to zero + * for the single GTI when there are no + * Good Times. + * 08/23/07 1.11 wvd Change malloc to cf_malloc. + * + ****************************************************************************/ + +#include +#include +#include +#include "calfuse.h" + +int +cf_set_good_time_intervals(fitsfile *infits, long nseconds, + float *timeline_time, unsigned char *timeline_status, GTI *gti) +{ + char CF_PRGM_ID[] = "cf_set_good_time_intervals"; + char CF_VER_NUM[] = "1.11"; + + char daynight[FLEN_VALUE], instmode[FLEN_VALUE]; + int in_bad; /* True between good-time intervals */ + int day=FALSE, night=FALSE, errflg=0, status=0; + long j, jj; + float exptime=0.; + double last_good_time=-99; + unsigned char TEMPORAL_MASK; + + cf_error_init(CF_PRGM_ID, CF_VER_NUM, stderr); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Begin Processing"); + + if ((errflg = cf_proc_check(infits, CF_PRGM_ID) )) return errflg; + + /* Read and interpret DAYNIGHT keyword. */ + + FITS_read_key(infits, TSTRING, "DAYNIGHT", daynight, NULL, &status); + if (!strncmp(daynight, "D", 1) || !strncmp(daynight, "d", 1)) { + day = TRUE; + } + else if (!strncmp(daynight, "N", 1) || !strncmp(daynight, "n", 1)) { + night = TRUE; + } + else if (!strncmp(daynight, "B", 1) || !strncmp(daynight, "b", 1)) { + day = night = TRUE; + } + else + cf_if_error("Unknown DAYNIGHT keyword value: %s", daynight); + cf_verbose(3, "DAYNIGHT flag set to %s", daynight); + + /* + * Read INSTMODE keyword. If in HIST mode, mask out + * LIMB, SAA, and BRST flags. TEMPORAL_DAY is the default. + */ + TEMPORAL_MASK = TEMPORAL_DAY; + FITS_read_key(infits, TSTRING, "INSTMODE", instmode, NULL, &status); + if (!strncmp(instmode, "HIST", 4)) { + TEMPORAL_MASK |= TEMPORAL_LIMB; + TEMPORAL_MASK |= TEMPORAL_SAA; + TEMPORAL_MASK |= TEMPORAL_BRST; + } + + /* + * Determine limits of good-time intervals. + */ + gti->start = (double *) cf_malloc(sizeof(double)*nseconds); + gti->stop = (double *) cf_malloc(sizeof(double)*nseconds); + + in_bad = TRUE; + jj = -1; + for (j = 0; j < nseconds; j++) { + /* + * If we are in a good time interval and were in a bad one, + * increment jj and set gti->start. + */ + if (!(timeline_status[j] & ~TEMPORAL_MASK) && + ((day && (timeline_status[j] & TEMPORAL_DAY)) || + (night && (timeline_status[j] ^ TEMPORAL_DAY)))) { + if (in_bad) { + jj++; + gti->start[jj] = timeline_time[j]; + in_bad = FALSE; + } + /* + * If we are in a good time interval and were in a good one, + * update last_good_time. + */ + last_good_time = timeline_time[j]; + } + /* + * If we are in a bad time interval and were in a good one, + * set in_bad to TRUE and update gti->stop. + */ + else if (in_bad == FALSE) { + gti->stop[jj] = timeline_time[j]; + in_bad = TRUE; + } + } + gti->ntimes = jj + 1; + + /* If the entire exposure is bad, return a zero-length GTI. */ + if (gti->ntimes == 0) { + gti->ntimes = 1; + gti->start[0] = gti->stop[0] = 0; + } + + /* Calculate total exposure time and write it to file header */ + for (j = 0; j < gti->ntimes; j++) + exptime += gti->stop[j] - gti->start[j]; + FITS_update_key(infits, TFLOAT, "EXPTIME", &exptime, NULL, &status); + + /* Results to trailer file. */ + cf_verbose(2, "GTI's:\t START\t STOP"); + for (j = 0; j < gti->ntimes; j++) + cf_verbose(2, "%3d\t%6.0f\t%6.0f", j, gti->start[j], gti->stop[j]); + cf_verbose(2, "Total EXPTIME = %6.0f", exptime); + + cf_proc_update(infits, CF_PRGM_ID, "COMPLETE"); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Done processing"); + return status; +} diff --git a/src/libcf/cf_set_photon_flags.c b/src/libcf/cf_set_photon_flags.c new file mode 100644 index 0000000..de2b623 --- /dev/null +++ b/src/libcf/cf_set_photon_flags.c @@ -0,0 +1,425 @@ +/***************************************************************************** + * Johns Hopkins University + * Center For Astrophysical Sciences + * FUSE + ***************************************************************************** + * + * Synopsis: cf_set_photon_flags(fitsfile *infits, long nevents, + * float *photon_time, + * float *photon_weight, + * unsigned char *photon_status, + * unsigned char *photon_locflag, + * long nseconds, float *timeline_time, + * unsigned char *timeline_status); + * + * Description: Copy status flags from the timeline table to the photon list. + * Update header keywords. + * + * For histogram data, we set only the DAY flag. + * Other situations are treated as follows: + * + * DAY All photons flagged if exposure >10% day + * + * LIMB True for all if true for one. + * SAA Do not flag photons or modify EXPTIME. + * BRST Instead, set header keyword EXP_STAT. + * Ignore all violations during the + * first and last 20 seconds of an exposure. + * + * HV Modify EXPTIME, but do not flag photons. + * JITR Ditto. + * + * OPUS Ignore for now. + * USER Ignore for now. + * + * Arguments: fitsfile *infits Input FITS file pointer + * long nevents Number of points in the photon list + * float *photon_time Time array of photon events + * float *photon_weight Scale factor for each photon + * unsigned char *photon_status Status flags for photon events + * unsigned char *photon_locflag Location flags for photon events + * long nseconds Number of points in the timeline table + * float *timeline_time Time array of timeline list + * unsigned char *timeline_status Status flags for timeline list + * + * Calls: + * + * Returns: 0 on success + * + * History: 10/31/02 1.1 jch Initial coding + * 12/20/02 1.3 jch Make sure the flags are "unsigned" char + * 05/09/03 1.4 wvd Change EXP* keywords to type long. + * Consider DAYNIGHT keyword in evaluation + * of NBADEVNT and EXP_BAD. + * Use frame_tolerance in time comparison. + * Use photon_locflag in counting NBADEVNT + * 05/20/03 1.5 rdr Add call to cf_proc_check + * 05/29/03 1.6 wvd Modify to handle HIST data: + * Use single flag for all photon events. + * Ignore LIMB, SAA, and BRST flags when + * counting EXP_BAD. Scale NBADEVNT by + * photon_weight[i]/TOT_DEAD. + * 06/02/03 1.7 wvd Properly deal with GTI's. + * 07/14/03 1.8 wvd Read DAYNIGHT from SCRN_CAL and + * populate IDF header keyword. + * Use FRAME_TOLERANCE from calfuse.h. + * 09/15/03 1.9 wvd Copy flags only to photons whose times + * are within 1s of timeline table time. + * 10/02/03 1.10 wvd Change timeline table: no breaks in + * time; add TEMPORAL_OPUS flag. + * 10/13/03 1.11 wvd Use same scheme for calculating + * EXP_BAD and exp_screen. + * 04/20/04 1.12 bjg Cosmetic change to prevent + * compiler warning with gcc -Wall + * 05/20/04 1.13 wvd Don't flag HIST photons as bad + * when HV or JITR are bad. + * We'll reduce EXPTIME instead. + * 06/01/04 1.14 wvd For HIST data, set only DAY flag. + * Write other flags to EXP_STAT keyword. + * 06/28/04 1.15 wvd If > 90% of exposure is lost to a + * burst, jitter, etc., write cause to + * trailer file. + * 03/24/05 1.16 wvd If EXP_STAT != 0, don't change it. + * 01/01/07 1.17 wvd Remove mention of FIFO flag. + * 07/18/08 1.18 wvd If EXP_STAT = 2, target is bright + * earth or airglow. Set limb-angle + * flags to zero. + * 08/22/08 1.19 wvd Compare EXP_STAT to TEMPORAL_LIMB, + * rather than a particular value. + * + ****************************************************************************/ + +#include +#include +#include "calfuse.h" + +#define HIST_PAD 20 /* Ignore first and last 20 s of each exposure. */ + +/* + * Compute integration time lost to a particular screening step. + * Ignore times outside of OPUS-defined good-time intervals. + */ +static long +time_loss(long nseconds, unsigned char *timeline_status, + unsigned char criterion) +{ + long exp_screen = 0, j; + + for (j = 0; j < nseconds; j++) { + if (timeline_status[j] & TEMPORAL_OPUS) continue; + if (timeline_status[j] & criterion) exp_screen++; + } + + return(exp_screen); +} + + +/* + * Compute integration time lost to a particular screening step, + * but ignore first and last HIST_PAD seconds of exposure. + */ +static long +time_loss_pad(long nseconds, unsigned char *timeline_status, + unsigned char criterion) +{ + long exp_screen = 0, j; + + for (j = HIST_PAD; j < nseconds - HIST_PAD; j++) { + if (timeline_status[j] & TEMPORAL_OPUS) continue; + if (timeline_status[j] & criterion) exp_screen++; + } + return (exp_screen); +} + + +/* + * In HIST mode, generate a status flag good for all photons. + * Except for D/N flag, we ignore first and last 20 seconds of exposure. + * D/N flag is written to TEMPORAL_MASK. + * LIMB/SAA/BRST flags are written to EXP_STAT. + */ +static void +generate_temporal_mask(float rawtime, long nseconds, float *timeline_time, + unsigned char *timeline_status, unsigned char *TEMPORAL_MASK, + unsigned char *EXP_STAT, char *comment) +{ + long exp_day; + + *EXP_STAT = *TEMPORAL_MASK = 0; + + /* + * Day if exp_day > 10% of total exposure time. + */ + exp_day=time_loss(nseconds, timeline_status, TEMPORAL_DAY); + if (exp_day * 10 > rawtime) { + *TEMPORAL_MASK = TEMPORAL_DAY; + sprintf(comment, "Exposure more than 10 percent day"); + cf_verbose(1, comment); + } + /* + * If exposure is less than 40 seconds long, we're done. + */ + if (rawtime < 2. * HIST_PAD) return; + + /* + * Are there limb-angle violations? + */ + if (time_loss_pad(nseconds, timeline_status, TEMPORAL_LIMB)) { + *EXP_STAT |= TEMPORAL_LIMB; + sprintf(comment, "Data suspect: Limb-angle violation"); + cf_verbose(1, comment); + } + /* + * Do we ever enter the SAA? + */ + if (time_loss_pad(nseconds, timeline_status, TEMPORAL_SAA)) { + *EXP_STAT |= TEMPORAL_SAA; + sprintf(comment, "Data suspect: SAA violation"); + cf_verbose(1, comment); + } + /* + * Are there any bursts? + */ + if (time_loss_pad(nseconds, timeline_status, TEMPORAL_BRST)) { + *EXP_STAT |= TEMPORAL_BRST; + sprintf(comment, "Data suspect: Burst detected"); + cf_verbose(1, comment); + } + + /* + * Is the detector voltage ever too low? + * If so, just issue a warning; we'll modify the exposure time later. + */ + if (time_loss_pad(nseconds, timeline_status, TEMPORAL_HV)) + cf_verbose(1, "EXPTIME modified: Detector voltage low."); + /* + * Was any time rejected by the jitter routine? + * If so, just issue a warning; we'll modify the exposure time later. + */ + if (time_loss_pad(nseconds, timeline_status, TEMPORAL_JITR)) + cf_verbose(1, "EXPTIME modified: Target out of aperture."); + + return; +} + + +int +cf_set_photon_flags(fitsfile *infits, long nevents, float *photon_time, + float *photon_weight, unsigned char *photon_status, + unsigned char *photon_locflag, long nseconds, + float *timeline_time, unsigned char *timeline_status) +{ + char CF_PRGM_ID[] = "cf_set_photon_flags"; + char CF_VER_NUM[] = "1.19"; + + char comment[FLEN_COMMENT], daynight[FLEN_KEYWORD]; + char instmode[FLEN_KEYWORD], scrnfile[FLEN_KEYWORD]; + long i, j, k; + + long nbadevnt=0; /* number of events deleted in screening */ + long exp_bad=0; /* integration time lost to screening */ + long exp_brst=0; /* integration time lost to event bursts */ + long exp_hv=0; /* integration time lost to low detector voltage */ + long exp_jitr=0; /* integration time lost to jitter */ + long exp_limb=0; /* integration time with low limb angle */ + long exp_saa=0; /* integration time while in SAA */ + long exp_day=0; /* integration time during day after screening */ + long expnight=0; /* integration time during night after screening */ + int day = FALSE, night = FALSE; + int errflg = 0; /* value returned by cf_proc_check */ + int status = 0; /* CFITSIO status */ + int expstat; /* initial value of EXP_STAT keyword */ + float deadtime, rawtime; + fitsfile *scrnfits; + unsigned char EXP_STAT, TEMPORAL_MASK; + + cf_error_init(CF_PRGM_ID, CF_VER_NUM, stderr); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Begin Processing"); + + if ((errflg = cf_proc_check(infits, CF_PRGM_ID) )) return errflg; + + /* Read and interpret DAYNIGHT keyword. Copy to IDF header. */ + + FITS_read_key(infits, TSTRING, "SCRN_CAL", scrnfile, NULL, &status); + FITS_open_file(&scrnfits, cf_parm_file(scrnfile), READONLY, &status); + FITS_read_key(scrnfits, TSTRING, "DAYNIGHT", daynight, NULL, &status); + FITS_close_file(scrnfits, &status); + + if (!strncmp(daynight, "D", 1) || !strncmp(daynight, "d", 1)) { + day = TRUE; + } + else if (!strncmp(daynight, "N", 1) || !strncmp(daynight, "n", 1)) { + night = TRUE; + } + else if (!strncmp(daynight, "B", 1) || !strncmp(daynight, "b", 1)) { + day = night = TRUE; + } + else + cf_if_error("Unknown DAYNIGHT keyword value: %s", daynight); + + /* + * Read EXP_STAT, RAWTIME, INSTMODE and TOT_DEAD keywords. + */ + FITS_read_key(infits, TINT, "EXP_STAT", &expstat, NULL, &status); + FITS_read_key(infits, TFLOAT, "RAWTIME", &rawtime, NULL, &status); + FITS_read_key(infits, TSTRING, "INSTMODE", instmode, NULL, &status); + FITS_read_key(infits, TFLOAT, "TOT_DEAD", &deadtime, NULL, &status); + + /* + * If EXP_STAT = TEMPORAL_LIMB, target is bright earth or airglow. + * Compute EXP_LIMB, then set limb-angle flags to 0. + */ + exp_limb=time_loss(nseconds, timeline_status, TEMPORAL_LIMB); + if (expstat == (int) TEMPORAL_LIMB) + for (i = 0; i < nseconds-1; i++) + timeline_status[i] &= ~TEMPORAL_LIMB; + + /* + * If in HIST mode: + * Generate TEMPORAL_MASK + * Copy status flags from TEMPORAL_MASK to photon list. + * Count bad photons. + */ + if (!strncmp(instmode, "HIST", 4)) { + generate_temporal_mask(rawtime, nseconds, timeline_time, + timeline_status, &TEMPORAL_MASK, &EXP_STAT, comment); + for (i = 0; i < nevents; i++) { + photon_status[i] = TEMPORAL_MASK; + /* + * A bad photon is one for which + * - something other than AIRGLOW is wrong; or + * - you don't want day, but this one is; or + * - you don't want night, but this one is. + */ + if ((photon_locflag[i] & ~LOCATION_AIR) || + (!day && (photon_status[i] & TEMPORAL_DAY)) || + (!night && (photon_status[i] ^ TEMPORAL_DAY))) + nbadevnt += (long)(photon_weight[i]/deadtime + 0.5); + } + if (EXP_STAT && !expstat) + FITS_update_key(infits, TBYTE, "EXP_STAT", &EXP_STAT, + comment, &status); + } + + /* + * If in TTAG mode: + * Copy status flags from timeline table to photon list. + * Confirm that photon time is included in timeline table. + * Count bad photons. + */ + else { + for (i = k = 0; i < nevents; i++) { + while (photon_time[i] > timeline_time[k+1]-FRAME_TOLERANCE && + k < nseconds-1) { k++; } + + if (photon_time[i] - timeline_time[k] < 2.0) + photon_status[i] = timeline_status[k]; + else + cf_if_warning("Time %g not included in timeline table", + photon_time[i]); + + /* + * A bad photon is one for which + * - something other than DAYNIGHT is wrong; or + * - something other than AIRGLOW is wrong; or + * - you don't want day, but this one is; or + * - you don't want night, but this one is. + */ + if ((photon_status[i] & ~TEMPORAL_DAY) || + (photon_locflag[i] & ~LOCATION_AIR) || + (!day && (photon_status[i] & TEMPORAL_DAY)) || + (!night && (photon_status[i] ^ TEMPORAL_DAY))) + nbadevnt++; + } + } + + /* + * Now count day, night, and bad seconds. + * If in HIST mode, mask out LIMB, SAA, and BRST flags. + * Exclude OPUS-defined bad times. + */ + TEMPORAL_MASK = TEMPORAL_DAY; + + if (!strncmp(instmode, "HIST", 4)) { + TEMPORAL_MASK |= TEMPORAL_LIMB; + TEMPORAL_MASK |= TEMPORAL_SAA; + TEMPORAL_MASK |= TEMPORAL_BRST; + } + + for (j = 0; j < nseconds; j++) { + if (timeline_status[j] & TEMPORAL_OPUS) + continue; + if (timeline_status[j] & ~TEMPORAL_MASK) + exp_bad++; + else if (timeline_status[j] & TEMPORAL_DAY) + exp_day++; + else + expnight++; + } + /* + * If user rejects either day or night data, add to EXP_BAD. + * If user rejects night data, set EXPNIGHT = 0. + */ + if (!day) { + exp_bad += exp_day; + } + if (!night) { + exp_bad += expnight; + expnight = 0; + } + + /* + * Compute EXP_BRST + */ + exp_brst=time_loss(nseconds, timeline_status, TEMPORAL_BRST); + /* + * Compute EXP_HV + */ + exp_hv=time_loss(nseconds, timeline_status, TEMPORAL_HV); + /* + * Compute EXP_JITR + */ + exp_jitr=time_loss(nseconds, timeline_status, TEMPORAL_JITR); + /* + * Compute EXP_LIMB (already done) + exp_limb=time_loss(nseconds, timeline_status, TEMPORAL_LIMB); + */ + /* + * Compute EXP_SAA + */ + exp_saa=time_loss(nseconds, timeline_status, TEMPORAL_SAA); + + /* + * If data are in time-tag mode and more than 90% of time was + * was rejected by screening, say why. + */ + if (!strncmp(instmode, "TTAG", 4)) { + if (exp_brst > 0.9 * rawtime) + cf_verbose(1, "%d sec lost to bursts.", exp_brst); + if (exp_hv > 0.9 * rawtime) + cf_verbose(1, "%d sec lost to low voltage.", exp_hv); + if (exp_jitr > 0.9 * rawtime) + cf_verbose(1, "%d sec lost to jitter.", exp_jitr); + if (exp_limb > 0.9 * rawtime) + cf_verbose(1, "%d sec lost to low limb angle.", exp_limb); + if (exp_saa > 0.9 * rawtime) + cf_verbose(1, "%d sec lost to SAA.", exp_saa); + } + + /* + * Update the header keywords + */ + FITS_update_key(infits, TLONG, "NBADEVNT", &nbadevnt, NULL, &status); + FITS_update_key(infits, TLONG, "EXP_BAD", &exp_bad, NULL, &status); + FITS_update_key(infits, TLONG, "EXP_BRST", &exp_brst, NULL, &status); + FITS_update_key(infits, TLONG, "EXP_HV", &exp_hv, NULL, &status); + FITS_update_key(infits, TLONG, "EXP_JITR", &exp_jitr, NULL, &status); + FITS_update_key(infits, TLONG, "EXP_LIM", &exp_limb, NULL, &status); + FITS_update_key(infits, TLONG, "EXP_SAA", &exp_saa, NULL, &status); + FITS_update_key(infits, TLONG, "EXPNIGHT", &expnight, NULL, &status); + FITS_update_key(infits, TSTRING, "DAYNIGHT", &daynight, NULL, &status); + + cf_proc_update(infits, CF_PRGM_ID, "COMPLETE"); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Done processing"); + return status; +} diff --git a/src/libcf/cf_set_user_gtis.c b/src/libcf/cf_set_user_gtis.c new file mode 100644 index 0000000..54a88d5 --- /dev/null +++ b/src/libcf/cf_set_user_gtis.c @@ -0,0 +1,100 @@ +/***************************************************************************** + * Johns Hopkins University + * Center For Astrophysical Sciences + * FUSE + ***************************************************************************** + * + * Synopsis: cf_set_user_gtis(fitsfile *infits, long nseconds, + * float *timeline_times, + * unsigned char *timeline_status); + * + * Description: Apply user-defined good time intervals to timeline table. + * + * Arguments: fitsfile *infits Input FITS file pointer + * long nseconds Number of points in the timeline table + * float *timeline_times Array of times + * unsigned char *timeline_status The status flag array + * + * Calls: + * + * Returns: 0 on success + * + * History: 09.10.03 1.1 bjg Initial coding + * + * 09.12.03 1.2 bjg Bug fix. When nusergti was zero or less + * this function set all the photons to + * bad. Now it doesn't change anything. + * 04.20.04 1.3 bjg Remove unused variables + * Change format to match arg type in + * sprintf. + * + * + ****************************************************************************/ + +#include +#include +#include "calfuse.h" + +int +cf_set_user_gtis(fitsfile *infits, long nseconds, + float *timeline_times, unsigned char *timeline_status) +{ + char CF_PRGM_ID[] = "cf_set_user_gtis"; + char CF_VER_NUM[] = "1.3"; + + int errflg=0, status=0, nusergti; + long i,n; + char file_name[FLEN_VALUE]; + float limit1,limit2; + char keywd1[FLEN_KEYWORD],keywd2[FLEN_KEYWORD]; + fitsfile *scrnfits; + + cf_error_init(CF_PRGM_ID, CF_VER_NUM, stderr); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Begin Processing"); + + if ((errflg = cf_proc_check(infits, CF_PRGM_ID) )) return errflg; + + /* + * Open the screening parameters file and read the good time intervals. + */ + FITS_read_key(infits, TSTRING, "SCRN_CAL", file_name, NULL, &status); + FITS_open_file(&scrnfits, cf_parm_file(file_name), READONLY, &status); + + FITS_read_key(scrnfits, TINT, "NUSERGTI", &nusergti, NULL, &status); + + if (nusergti>0){ + + i=0; + + for (n=1;n<=nusergti;n++){ + sprintf(keywd1, "GTIBEG%02ld",n); + FITS_read_key(scrnfits, TFLOAT, keywd1, &limit1, NULL, &status); + sprintf(keywd2, "GTIEND%02ld",n); + FITS_read_key(scrnfits, TFLOAT, keywd2, &limit2, NULL, &status); + + + while ((i + +int +cf_source_aper(fitsfile *infits, int *active_ap ) +{ + /* char CF_PRGM_ID[] = "cf_source_aper"; */ + /* char CF_VER_NUM[] = "1.8"; */ + + char aper[FLEN_CARD], src[FLEN_CARD]; + int status=0, hdutype, src_type; + + /* Determine the active aperture */ + FITS_movabs_hdu(infits, 1, &hdutype, &status); + FITS_read_key(infits, TSTRING, "APERTURE", aper, NULL, &status); + + /* Specify the channels of the active aperture */ + if (!strncmp(aper,"HIRS",4)) { + active_ap[0] = 1; + active_ap[1] = 5; } + else if (!strncmp(aper,"MDRS",4)) { + active_ap[0] = 2; + active_ap[1] = 6; } + else if (!strncmp(aper,"LWRS",4) || !strncmp(aper,"RFPT",4)) { + active_ap[0] = 3; + active_ap[1] = 7; + } + else + cf_if_error("APERTURE keyword corrupted."); + cf_verbose(3, "APERTURE = %s, channels are %d and %d", + aper, active_ap[0], active_ap[1]); + + FITS_read_key(infits, TSTRING,"SRC_TYPE", src, NULL, &status); + src_type = 0; + if (!strncmp(src,"E",1) || !strncmp(src,"e",1) ) src_type = 1; + + cf_verbose(3, "SRC_TYPE = %s, source type = %d", src, src_type); + return src_type; +} diff --git a/src/libcf/cf_standard_or_optimal_extraction.c b/src/libcf/cf_standard_or_optimal_extraction.c new file mode 100644 index 0000000..2b2a6fa --- /dev/null +++ b/src/libcf/cf_standard_or_optimal_extraction.c @@ -0,0 +1,75 @@ +/***************************************************************************** + * Johns Hopkins University + * Center For Astrophysical Sciences + * FUSE + ***************************************************************************** + * + * Synopsis: cf_standard_or_optimal_extraction (fitsfile *header, + * int *optimal) + * + * Description: Sets optimal to TRUE if optimal extraction is desired. + * FALSE if RUN_OPTI = 'NO' in parm*.fit file. + * FALSE if SRC_TYPE[0] = 'E' in file header. + * + * Arguments: fitsfile *header Pointer to IDF FITS file header + * int *optimal TRUE if optimal extraction desired + * + * Calls: + * + * Returns: 0 on success + * + * History: 03/02/03 1.1 wvd Initial coding. + * 03/12/03 1.2 wvd Write value of optimal to trailer file. + * 03/19/03 1.3 wvd Read SRC_TYPE, not SP_TYPE. + * 03/19/03 1.4 wvd Add call to cf_timestamp at start. + * Change printf to cf_verbose + * 09/30/03 1.5 wvd Check for lower-case value of + * RUN_OPTI. + * 03/15/05 1.6 wvd No optimal extraction for HIST targets + * unless try_optimal = TRUE; + * 03/18/05 1.7 wvd v1.6 was a bad idea. Returning to v1.5 + * + ****************************************************************************/ + +#include +#include "calfuse.h" + +static char CF_PRGM_ID[] = "cf_standard_or_optimal_extraction"; +static char CF_VER_NUM[] = "1.7"; + +int +cf_standard_or_optimal_extraction(fitsfile *header, int *optimal) +{ + char parm_file[FLEN_VALUE], instmode[FLEN_VALUE]; + char run_opti[FLEN_VALUE], src_type[FLEN_VALUE]; + int status=0; + fitsfile *parmfits; + + cf_error_init(CF_PRGM_ID, CF_VER_NUM, stderr); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Begin processing"); + + /* Read SRC_TYPE from IDF header. */ + FITS_read_key(header, TSTRING, "SRC_TYPE", src_type, NULL, &status); + FITS_read_key(header, TSTRING, "INSTMODE", instmode, NULL, &status); + + /* Read RUN_OPTI from PARM_CAL. */ + FITS_read_key(header, TSTRING, "PARM_CAL", parm_file, NULL, &status); + FITS_open_file(&parmfits, cf_parm_file(parm_file), READONLY, &status); + FITS_read_key(parmfits, TSTRING, "RUN_OPTI", run_opti, NULL, &status); + FITS_close_file(parmfits, &status); + + /* Determine value of optimal. */ + *optimal = TRUE; + if (*run_opti != 'Y' && *run_opti != 'y') { + cf_verbose (1, "RUN_OPTI = %s. No optimal extraction.", run_opti); + *optimal = FALSE; + } + if (*src_type != 'P') { + cf_verbose (1, "SRC_TYPE = %s. No optimal extraction.", src_type); + *optimal = FALSE; + } + if (*optimal) cf_verbose (1, "Attempting optimal extraction."); + + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Done processing"); + return status; +} diff --git a/src/libcf/cf_target_count_rate.c b/src/libcf/cf_target_count_rate.c new file mode 100644 index 0000000..eab5b26 --- /dev/null +++ b/src/libcf/cf_target_count_rate.c @@ -0,0 +1,112 @@ +/************************************************************************** + * Johns Hopkins University + * Center for Astrophysical Sciences + * FUSE + ************************************************************************* + * + * Synopsis: cf_target_count_rate(header, nevents, ptime, weight, + * channel, locflags, ntimes, ttime, rate_lif, rate_sic) + * + * Description: Determines the count rate in the target aperture for both + * LiF and SiC channels. Excludes airglow lines. + * + * Arguments: fitsfile *header : pointer to IDF header + * long nevents : number of photon events in the file + * float *ptime : detection time for each photon + * float *weight : weight associated with each photon + * unsigned char *channel: aperture associated with each photon + * unsigned char *locflags: location flag array - flags the + * geocoronal photons + * long ntimes : number of seconds tabulated in timeline + * float *ttime : tabulated times in the timeline + * float *rate_lif, *rate_sic : + * count rates through the Lif and SiC + * apertures, excluding geocoronal emission + * + * Calibration files required: None + * + * Returns: 0 on success + * + * + * HISTORY: 03/03/03 v1.1 RDR started work + * 03/05/03 v1.2 wvd change name of subroutine & install + * 03/10/03 v1.21 rdr changed specification of locflags + * from char to unsigned char + * 05/20/03 v1.3 rdr Added call to cf_proc_check + * 05/22/03 v1.5 wvd Direct cf_error_init to stderr + * 06/02/03 v1.6 wvd Implement cf_verbose throughout. + * 06/04/03 v1.7 wvd Revise scheme for summing counts. + * 08/20/03 v1.8 wvd Use FRAME_TOLERANCE from calfuse.h, + * change channel to unsigned char. + * 09/15/03 v1.9 wvd Test that photon times match + * timeline times to within 1 sec. + * 10/06/03 v1.10 wvd Changed screen to locflags throughout. + * 12/29/06 v1.11 wvd Sum weights rather than counts. + * Convert output arrays to type float. + * Scale HIST count rate by DET_DEAD. + * 04/07/07 v1.12 wvd Clean up compiler warnings. + * 04/07/07 v1.13 wvd Clean up compiler warnings. + * + **************************************************************************/ + +#include +#include "calfuse.h" + +int +cf_target_count_rate(fitsfile *header, long nevents, float *ptime, + float *weight, unsigned char *channel, unsigned char *locflags, + long ntimes, float *ttime, float *rate_lif, float *rate_sic) { + + char CF_PRGM_ID[] = "cf_target_count_rate" ; + char CF_VER_NUM[] = "1.13" ; + + char instmode[FLEN_VALUE]; + int errflg=0, status=0, active_ap[2] ; + float delta_max = 1.0 + FRAME_TOLERANCE; + float det_dead; + long j, k ; + + /* Initialize error checking. */ + cf_error_init(CF_PRGM_ID, CF_VER_NUM, stderr); + + /* Enter a time stamp into the log. */ + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Begin Processing"); + + /* Confirm that this subroutine should be run. */ + if ((errflg = cf_proc_check(header, CF_PRGM_ID))) return errflg; + + /* Determine the source aperture from the header data. */ + FITS_read_key(header, TSTRING, "INSTMODE", instmode, NULL, &status); + (void) cf_source_aper(header, active_ap) ; + + /* + * For histogram data, scale the LiF and SiC count rates, which come + * from the housekeeping data file, by DET_DEAD. + */ + if (!strncmp(instmode, "HIST", 4)) { + FITS_read_key(header, TFLOAT, "DET_DEAD", &det_dead, NULL, &status); + for (k = 0; k < ntimes; k++) rate_lif[k] *= det_dead; + for (k = 0; k < ntimes; k++) rate_sic[k] *= det_dead; + } + + /* + * For time-tag data, count the photons arriving during each second + * of the exposure. Exclude events near airglow regions. + */ + else { + for (k = 0; k < ntimes; k++) rate_lif[k] = rate_sic[k] = 0.; + for (j=k=0; j +#include +#include +#include "calfuse.h" + +#define STIMS (LOCATION_STIML|LOCATION_STIMR) + +static int +cf_estimate_drift_coefficients (fitsfile *header, float *x0, float *x1, + float *y0, float *y1) +{ + char stimfile[FLEN_FILENAME]; + int status=0; + long j, jmax; + float *x0_array=NULL, *x1_array=NULL, *y0_array=NULL, *y1_array=NULL; + double expstart, *mjd=NULL; + fitsfile *stimfits; + + /* Read header keywords. */ + FITS_read_key(header, TDOUBLE, "EXPSTART", &expstart, NULL, &status); + FITS_read_key(header, TSTRING, "STIM_CAL", stimfile, NULL, &status); + cf_verbose(3, "Drift-coefficient calibration file = %s", stimfile); + + /* Read drift-coefficients from the calibration file. */ + FITS_open_file(&stimfits, cf_cal_file(stimfile), READONLY, &status); + FITS_movabs_hdu(stimfits, 2, NULL, &status); + jmax = cf_read_col(stimfits, TDOUBLE, "MJD", (void *) &mjd); + jmax = cf_read_col(stimfits, TFLOAT, "X0", (void *) &x0_array); + jmax = cf_read_col(stimfits, TFLOAT, "X1", (void *) &x1_array); + jmax = cf_read_col(stimfits, TFLOAT, "Y0", (void *) &y0_array); + jmax = cf_read_col(stimfits, TFLOAT, "Y1", (void *) &y1_array); + FITS_close_file(stimfits, &status); + + /* Find the coefficients appropriate for this exposure. */ + j = 0; + while (j < jmax-1 && mjd[j+1] < expstart) j++; + *x0 = x0_array[j]; + *x1 = x1_array[j]; + *y0 = y0_array[j]; + *y1 = y1_array[j]; + + free(mjd); + free(x0_array); + free(x1_array); + free(y0_array); + free(y1_array); + + return status; +} + + +static int +cf_get_stim_positions(long nevents, float *xfarf, float *yfarf, float *weight, + unsigned char *loc, float width, float *stimlx, float *stimly, + float *stimrx, float *stimry) +{ + int stim_status=0; + long j; + double lx=0., ly=0., rx=0., ry=0., nl=0., nr=0.; + + cf_verbose(3,"initial: stimlx = %0.1f, stimly=%0.1f, width=%0.1f ", + *stimlx, *stimly, width) ; + cf_verbose(3,"initial: stimrx = %0.1f, stimry=%0.1f, width=%0.1f ", + *stimrx, *stimry, width) ; + + for (j=0; j= *stimlx-width && xfarf[j] <= *stimlx+width && + yfarf[j] >= *stimly-width && yfarf[j] <= *stimly+width) { + lx += xfarf[j] * weight[j]; + ly += yfarf[j] * weight[j]; + nl += weight[j]; + loc[j] |= LOCATION_STIML; + } + else if (xfarf[j] >= *stimrx-width && xfarf[j] <= *stimrx+width && + yfarf[j] >= *stimry-width && yfarf[j] <= *stimry+width) { + rx += xfarf[j] * weight[j]; + ry += yfarf[j] * weight[j]; + nr += weight[j]; + loc[j] |= LOCATION_STIMR; + } + else { + loc[j] &= ~STIMS; + } + } + + cf_verbose(3,"nl=%0.1f, nr=%0.1f ",nl,nr) ; + + if (nl > 500) { + *stimlx = lx/nl; + *stimly = ly/nl; + } else { + cf_if_warning("Cannot determine left STIM position. Estimating."); + stim_status = 1; + } + if (nr > 500) { + *stimrx = rx/nr; + *stimry = ry/nr; + } else { + cf_if_warning("Cannot determine right STIM position. Estimating."); + stim_status = 1; + } + + if (!stim_status) { + cf_verbose(3,"after iteration: stimlx = %0.1f, stimly=%0.1f ", *stimlx, *stimly); + cf_verbose(3,"after iteration: stimrx = %0.1f, stimry=%0.1f ", *stimrx, *stimry); + } + + return stim_status; +} + +int +cf_thermal_distort(fitsfile *header, long nevents, float *xfarf, + float *yfarf, float *weight, unsigned char *locflags) +{ + char CF_PRGM_ID[] = "cf_thermal_distort"; + char CF_VER_NUM[] = "1.16"; + + char elecfile[FLEN_VALUE], detector[FLEN_VALUE]; + char keyword[FLEN_KEYWORD]; + int errflg=0, status=0, stim_status=0; + long j; + float farflx, farfly, farfrx, farfry, x0, x1, y0, y1; + float stimlx, stimly, stimrx, stimry, oldlx, oldly, oldrx, oldry; + float width=128., tol=0.01; + fitsfile *elecfits; + + cf_error_init(CF_PRGM_ID, CF_VER_NUM, stderr); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Begin Processing"); + + if ((errflg = cf_proc_check(header, CF_PRGM_ID))) return errflg; + + FITS_read_key(header, TSTRING, "DETECTOR", detector, NULL, &status); + /* + * Get the name of the calibration file and open it + */ + FITS_read_key(header, TSTRING, "ELEC_CAL", elecfile, NULL, &status); + FITS_open_file(&elecfits, cf_cal_file(elecfile), READONLY, &status); + /* + * Read stim locations in FARF frame. + */ + FITS_read_key(elecfits, TFLOAT, "STIMWDTH", &width, NULL, &status); + FITS_read_key(elecfits, TFLOAT, "STIMTOLR", &tol, NULL, &status); + sprintf(keyword, "STIMLX%s", detector); + FITS_read_key(elecfits, TFLOAT, keyword, &farflx, NULL, &status); + sprintf(keyword, "STIMLY%s", detector); + FITS_read_key(elecfits, TFLOAT, keyword, &farfly, NULL, &status); + sprintf(keyword, "STIMRX%s", detector); + FITS_read_key(elecfits, TFLOAT, keyword, &farfrx, NULL, &status); + sprintf(keyword, "STIMRY%s", detector); + FITS_read_key(elecfits, TFLOAT, keyword, &farfry, NULL, &status); + FITS_close_file(elecfits, &status); + /* + * Get stim positions (iteratively). + */ + stimlx = farflx; stimly = farfly; + stimrx = farfrx; stimry = farfry; + do { + oldlx = stimlx; oldly = stimly; + oldrx = stimrx; oldry = stimry; + width /= 2.; + stim_status = cf_get_stim_positions(nevents, xfarf, yfarf, weight, + locflags, width, &stimlx, &stimly, &stimrx, &stimry); + if (!stim_status) + cf_verbose(3,"dstimlx=%.1f, dstimly=%.1f, dstimrx=%.1f," + "dstimry=%.1f ", fabs(oldlx-stimlx), fabs(oldly-stimly), + fabs(oldrx-stimrx), fabs(oldry-stimry) ) ; + } while (fabs(oldlx-stimlx) > tol && fabs(oldly-stimly) > tol && + fabs(oldrx-stimrx) > tol && fabs(oldry-stimry) > tol && + !stim_status); + /* + * Write stim pulse positions to file header. + */ + if (!stim_status) { + FITS_update_key(header, TFLOAT, "STIM_L_X", &stimlx, NULL, &status); + FITS_update_key(header, TFLOAT, "STIM_L_Y", &stimly, NULL, &status); + FITS_update_key(header, TFLOAT, "STIM_R_X", &stimrx, NULL, &status); + FITS_update_key(header, TFLOAT, "STIM_R_Y", &stimry, NULL, &status); + } + /* + * Calculate drift coefficients from stim pulse positions + */ + if (!stim_status) { + x0 = (stimlx*farfrx - stimrx*farflx)/(stimlx - stimrx); + x1 = (farflx - farfrx)/(stimlx - stimrx); + y0 = 0.5*((farfly + farfry) - (stimly + stimry)); + y1 = 1.0; + } + /* + * ...or estimate them from date of exposure. + */ + else + cf_estimate_drift_coefficients (header, &x0, &x1, &y0, &y1); + cf_verbose(2, "Drift coefficients: %f %f, %f %f", x0, x1, y0, y1); + /* + * Apply thermal correction to events in active area and + * stim-pulse regions. + */ + for (j=0; j +#include +#include +#include "calfuse.h" + +int +cf_time_xy_distort(fitsfile *header, long nevents, + float *xfarf, float *yfarf, unsigned char *locflags) +{ + char CF_PRGM_ID[] = "cf_time_xy_distort"; + char CF_VER_NUM[] = "1.4"; + + char tmxyfile[FLEN_VALUE]; + int errflg=0, hdutype, status=0, anynull=0; + int binfact, i, ii, i_max, tndx, xndx, yndx; + long j, xlen, ylen; + double expstart; + float *xstretch2d, *ystretch2d, xstretch1d[NXMAX], ystretch1d[NYMAX]; + fitsfile *tmxyfits; + + cf_error_init(CF_PRGM_ID, CF_VER_NUM, stderr); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Begin Processing"); + + if ((errflg = cf_proc_check(header, CF_PRGM_ID))) return errflg; + + /* + * Read MJD of exposure start. + */ + FITS_read_key(header, TDOUBLE, "EXPSTART", &expstart, NULL, &status); + + /* + * Read the X correction array. + * Note: the first column of the calibration array contains MJD. + */ + FITS_read_key(header, TSTRING, "TMXY_CAL", tmxyfile, NULL, &status); + cf_verbose(3, "Reading TMXY_CAL file %s", tmxyfile); + FITS_open_file(&tmxyfits, cf_cal_file(tmxyfile), READONLY, &status); + FITS_movabs_hdu(tmxyfits, 2, &hdutype, &status); + FITS_read_key(tmxyfits, TLONG, "NAXIS1", &xlen, NULL, &status); + FITS_read_key(tmxyfits, TLONG, "NAXIS2", &ylen, NULL, &status); + FITS_read_key(tmxyfits, TINT, "BIN_FACT", &binfact, NULL, &status); + xstretch2d = (float *) cf_malloc(sizeof(float)*xlen*ylen); + FITS_read_img(tmxyfits, TFLOAT, 1L, xlen*ylen, NULL, xstretch2d, + &anynull, &status); + + /* + * Find the row in the calibration array that corresponds to the + * exposure start time. + */ + i = 0; + while (expstart > *(xstretch2d+i*xlen) && i < ylen) i++; + tndx = i-1; + if (tndx < 0) tndx = 0; + cf_verbose(2,"EXPSTART = %g.", expstart); + cf_verbose(2,"Using X corrections for MJD >= %g", *(xstretch2d+tndx*xlen)); + if (tndx < ylen-1) + cf_verbose(2," and MJD < %g", + *(xstretch2d+(tndx+1)*xlen)); + + /* + * Now compute a 1-D array containing corrections to X + * coordinate as a function of X position on the detector. + * Shift information binned by BIN_FACT pixels. + * We interpolate to the nearest X pixel. Otherwise, + * counts pile up at the boundaries. + */ + i_max = (xlen-2) * binfact; + for (i = 0; i < i_max; i++) { + ii = (i/binfact) * binfact; + xstretch1d[i] = ((ii+binfact-i) * (xstretch2d+tndx*xlen)[1+i/binfact] + + (i-ii) * (xstretch2d+tndx*xlen)[2+i/binfact]) / binfact; + } + for ( ; i < NXMAX; i++) + xstretch1d[i] = (xstretch2d+tndx*xlen)[xlen-1]; + + /* + * Read the Y correction array. + */ + FITS_movabs_hdu(tmxyfits, 3, &hdutype, &status); + FITS_read_key(tmxyfits, TLONG, "NAXIS1", &xlen, NULL, &status); + FITS_read_key(tmxyfits, TLONG, "NAXIS2", &ylen, NULL, &status); + FITS_read_key(tmxyfits, TINT, "BIN_FACT", &binfact, NULL, &status); + ystretch2d = (float *) cf_malloc(sizeof(float)*xlen*ylen); + FITS_read_img(tmxyfits, TFLOAT, 1L, xlen*ylen, NULL, ystretch2d, + &anynull, &status); + FITS_close_file(tmxyfits, &status); + + /* + * Find the row in the calibration array that corresponds to the + * exposure start time. + */ + i = 0; + while (expstart > *(ystretch2d+i*xlen) && i < ylen) i++; + tndx = i-1; + if (tndx < 0) tndx = 0; + cf_verbose(3,"Using Y corrections for MJD >= %g", *(ystretch2d+tndx*xlen)); + if (tndx < ylen-1) + cf_verbose(3," and MJD < %g", + *(ystretch2d+(tndx+1)*xlen)); + + /* + * Now compute a 1-D array containing corrections to Y + * coordinate as a function of Y position on the detector. + */ + i_max = (xlen-2) * binfact; + for (i = 0; i < i_max; i++) { + ii = (i/binfact) * binfact; + ystretch1d[i] = ((ii+binfact-i) * (ystretch2d+tndx*xlen)[1+i/binfact] + + (i-ii) * (ystretch2d+tndx*xlen)[2+i/binfact]) / binfact; + } + for ( ; i < NYMAX; i++) + ystretch1d[i] = (ystretch2d+tndx*xlen)[xlen-1]; + cf_verbose(3, "For y = 430, ystretch = %f\n", ystretch1d[430]); + cf_verbose(3, "For y = 810, ystretch = %f\n", ystretch1d[810]); + + /* + * Loop through all events. Move only events in active region. + */ + for (j = 0; j < nevents; j++) { + if (!(locflags[j] & LOCATION_SHLD)) { + xndx = (int) xfarf[j]; + if (xndx < 0) xndx = 0; + else if (xndx >= NXMAX) xndx = NXMAX-1; + + yndx = (int) yfarf[j]; + if (yndx < 0) yndx = 0; + else if (yndx >= NYMAX) yndx = NYMAX-1; + + xfarf[j] += xstretch1d[xndx]; + yfarf[j] += ystretch1d[yndx]; + } + } + + free(xstretch2d); + free(ystretch2d); + + cf_proc_update(header, CF_PRGM_ID, "COMPLETE"); + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Done processing"); + return 0; +} diff --git a/src/libcf/cf_timestamp.c b/src/libcf/cf_timestamp.c new file mode 100644 index 0000000..52ef311 --- /dev/null +++ b/src/libcf/cf_timestamp.c @@ -0,0 +1,78 @@ +/***************************************************************************** + * Johns Hopkins University + * Center For Astrophysical Sciences + * FUSE + ***************************************************************************** + * + * Synopsis: cf_timestamp(const char *prgmid, const char *vernum, char *msg) + * + * Description: Writes a timestamp and the calling program name to stdout. + * + * Arguments: char *prgmid Name of the calling program + * char *msg Optional additional message string + * + * Returns: none + * + * History: 01/04/91 mlr Original "warn_str.c" for libhut + * 03/03/98 gak Adapted for placing timestamps in + * FUSE pipeline programs. + * 06/07/99 peb Added reporting of version number. + * 10/27/99 emm Added fflush(stdout) + * 04/23/01 wvd Change declaration of tim from + * long to time_t + * 03/19/03 peb Made this function a wrapper for + * cf_verbose. + * 03/25/03 peb Changed output to print time, program, + * version number and to use verbose_level + * when printing output + * level>=1 prints "Finished processing" + * level>=2 prints "Begin processing" + * 09/15/03 v1.5 wvd To reduce size of the trailer file, + * if verbose level = 1, print "Finished" + * only for top-level routines. + * 10/17/03 v1.6 wvd Use strcmp, rather than strncmp, to + * set this_is_a_top_level_routine. + * 10/30/03 1.7 peb Replaced cftime function with strftime + * for UNIX compatibility. + * + ****************************************************************************/ + +#include +#include +#include "calfuse.h" + +#define N_STYM 80 + +void cf_timestamp(const char *prgmid, const char *vernum, char *msg) +{ + char stym[N_STYM]={'\0'}; + char *top_level_routines[]=TOP_LEVEL_ROUTINES; + int i, this_is_a_top_level_routine = FALSE; + time_t tym; + + time(&tym); + strftime(stym, N_STYM, "%Y %b %e %T", localtime(&tym)); + + /* Compare program ID with list of top-level routines. */ + for (i = 0; i < NTOP_LEVEL_ROUTINES; i++) { + if (!strcmp(prgmid, top_level_routines[i])) { + this_is_a_top_level_routine = TRUE; + break; + } + } + + /* + * The following test should get most "Finished" or "Done" type of + * timestamps. For those not caught if might be best to change them to + * one of these two. + */ + if (((verbose_level == 1 && this_is_a_top_level_routine) || + (verbose_level > 1)) && + (strncmp(msg, "Finish", 6) == 0 || strncmp(msg, "Done", 4) == 0)) + printf("%s %s-%s: %s\n", stym, prgmid, vernum, "Finished processing"); + else if (verbose_level >= 2 && + (strncmp(msg, "Start", 5) == 0 || strncmp(msg, "Begin", 5) == 0)) + printf("%s %s-%s: %s\n", stym, prgmid, vernum, "Begin processing"); + + fflush(stdout); +} diff --git a/src/libcf/cf_velang.c b/src/libcf/cf_velang.c new file mode 100644 index 0000000..8395738 --- /dev/null +++ b/src/libcf/cf_velang.c @@ -0,0 +1,147 @@ +/***************************************************************************** + * Johns Hopkins University + * Center For Astrophysical Sciences + * FUSE + ***************************************************************************** + * + * Synopsis: cf_velang(fitsfile *outfits, double mjd) + * + * Description: Calculates the sun angle, moon angle, and conversions to + * heliocentric and LSR velocities at given mjd, which should be + * the middle of the exposure. For FUV images, the needed + * data is in the primary header, so we have to go back + * up to the top. For FES images, the data should be in + * each HDU, so you should call cf_velang_calc instead. + * + * Arguments: fitsfile *outfits Pointer to FITS file containing the + * input data and orbital elements + * double mjd The Modified Julian Date of the + * photon arrival time. + * + * Calls: slaDsep dsep.f + * slaRdplan rdplan.f + * + * History: 07/13/98 emm Begin work + * 06/10/99 emm Added keyword header update, added + * calculation of MOONANG. + * 06/11/99 emm Fixed some bugs that Jayant found. + * 06/21/99 jm Corrected name + * 07/16/99 emm Changed GEO_LON to GEO_LONG + * 07/21/99 peb RA and Dec now use RA_TARG and DEC_TARG + * 07/22/99 emm Added V_GEOCEN update. + * 07/23/99 emm Added cf_velang_calc for FES images. + * 05/31/00 peb Implemented cfortran.h calls for slalib + * functions. + * 04/01/03 v1.3 wvd Replaced printf with cf_verbose + * 04/04/03 v1.4 wvd Modifed calls to cf_verbose. + * 12/18/03 v1.5 bjg Change calfusettag.h to calfuse.h + * 07/06/06 v1.6 wvd Add call to pole_ang and populate + * header keyword POLEANGL. + * 03/07/07 v1.7 wvd Remove pos from call to space_vel. + * + ****************************************************************************/ + +#include + +#ifdef CFORTRAN +#include "cfortran.h" +PROTOCCALLSFFUN4(DOUBLE, SLA_DSEP, sla_dsep, DOUBLE, DOUBLE, DOUBLE, \ + DOUBLE) +#define slaDsep(A1, B1, A2, B2) \ + CCALLSFFUN4(SLA_DSEP, sla_dsep, DOUBLE, DOUBLE, DOUBLE, DOUBLE, \ + A1, B1, A2, B2) +PROTOCCALLSFSUB7(SLA_RDPLAN, sla_rdplan, DOUBLE, INT, DOUBLE, DOUBLE, \ + PDOUBLE, PDOUBLE, PDOUBLE) +#define slaRdplan(DATE, NP, ELONG, PHI, RA, DEC, DIAM) \ + CCALLSFSUB7(SLA_RDPLAN, sla_rdplan, DOUBLE, INT, DOUBLE, DOUBLE, \ + PDOUBLE, PDOUBLE, PDOUBLE, \ + DATE, NP, ELONG, PHI, RA, DEC, DIAM) +#else +#include "slalib.h" +#include "slamac.h" +#endif + +#include "calfuse.h" +#include "sgp4.h" + +SGP4 set_orbit_parms(fitsfile *); + +static void +cf_velang_calc(fitsfile *outfits, double mjd) +{ + int status=0; + char comment[FLEN_CARD]; + double ra, dec, geo_lon, geo_lat, mag_lat, pos[3], vel[3], gmst, helvel; + double ra_moon, dec_moon, moon_ang, dia_moon, vlsr1, vlsr2, sun_ang; + double geo_vel, pole_angle; + SGP4 sgp4; + + /* get the state vector at time mjd */ + sgp4 = set_orbit_parms(outfits); + SGP4_getStateVector(sgp4, mjd, pos, vel); + SGP4_precess(pos, mjd, MJD2000); SGP4_precess(vel, mjd, MJD2000); + + cf_verbose(2,"State vector at MJD=%14.6f days", mjd); + cf_verbose(2,"x=%14.6f y=%14.6f z=%14.6f km", pos[0], pos[1], pos[2]); + cf_verbose(2,"vx=%14.6f vy=%14.6f vz=%14.6f km/s",vel[0], vel[1], vel[2]); + + state_geod(pos, mjd, &geo_lon, &geo_lat, &gmst); + + mag_lat = geod_mag(geo_lon, geo_lat); + /* + * Note: this function has been changed to use RA_TARG and DEC_TARG + * keywords, because the RA_APER and DEC_APER keywords are currently + * not being set. + */ + FITS_read_key(outfits, TDOUBLE, "RA_TARG", &ra, comment, &status); + FITS_read_key(outfits, TDOUBLE, "DEC_TARG", &dec, comment, &status); + + geo_vel= space_vel(vel, ra, dec); + helvel = helio_vel(mjd, ra, dec); + vlsr1 = lsrk_vel(ra, dec); + vlsr2 = lsrd_vel(ra, dec); + + /* Calculate sun angle */ + sun_ang = solar_ang(mjd, ra, dec); + + /* Calculate moon angle */ +#ifdef CFORTRAN + slaRdplan(mjd, 3, geo_lon, geo_lat, ra_moon, dec_moon, dia_moon); +#else + slaRdplan(mjd, 3, geo_lon, geo_lat, &ra_moon, &dec_moon, &dia_moon); +#endif + moon_ang = slaDsep(ra*RADIAN, dec*RADIAN, ra_moon, dec_moon)/RADIAN; + + /* Calculate sun angle */ + pole_angle = pole_ang(pos, vel, ra, dec); + + FITS_update_key(outfits, TDOUBLE, "SUNANGLE", &sun_ang, NULL, &status); + FITS_update_key(outfits, TDOUBLE, "MOONANGL", &moon_ang, NULL, &status); + FITS_update_key(outfits, TDOUBLE, "POLEANGL", &pole_angle, NULL, &status); + FITS_update_key(outfits, TDOUBLE, "GEO_LONG", &geo_lon, NULL, &status); + FITS_update_key(outfits, TDOUBLE, "GEO_LAT", &geo_lat, NULL, &status); + FITS_update_key(outfits, TDOUBLE, "MAG_LAT", &mag_lat, NULL, &status); + FITS_update_key(outfits, TDOUBLE, "V_GEOCEN", &geo_vel, NULL, &status); + FITS_update_key(outfits, TDOUBLE, "V_HELIO", &helvel, NULL, &status); + FITS_update_key(outfits, TDOUBLE, "V_LSRDYN", &vlsr2, NULL, &status); + FITS_update_key(outfits, TDOUBLE, "V_LSRSTD", &vlsr1, NULL, &status); +} + + +void cf_velang(fitsfile *outfits, double mjd) +{ + int status=0, hdunum=0, hdutype; + /* + * The outfits file pointer may be down in one of the extensions + * whereas the orbital info is in the primary hdu. Therefore, + * record the current position, move to the primary header, + * read the orbital data, and return to the previous hdu. + */ + FITS_get_hdu_num(outfits, &hdunum); + FITS_movabs_hdu(outfits, 1, &hdutype, &status); + + cf_velang_calc(outfits, mjd); + + FITS_movabs_hdu(outfits, hdunum, &hdutype, &status); + +} diff --git a/src/libcf/cf_write_extracted_spectrum.c b/src/libcf/cf_write_extracted_spectrum.c new file mode 100644 index 0000000..90831c2 --- /dev/null +++ b/src/libcf/cf_write_extracted_spectrum.c @@ -0,0 +1,226 @@ +/************************************************************************** + * Johns Hopkins University + * Center for Astrophysical Sciences + * FUSE + ************************************************************************* + * + * synopsis: cf_write_extracted_spectrum(infile, aperture, nout, wave_out, + * flux_out, var_out, counts_out, weights_out, bkgd_out, + * bpix_out, outrootname) + * + * Description: Write the results of the data reduction to a file. + * Information from the header is used to generate the name + * of the output file. Aperture coding is as follows: + * + * 1-8 -> LiF[HIRS,MDRS,LWRS,PINH], SiC[HIRS,MDRS,LWRS,PINH] + * + * Arguments: fitsfile infile : pointer to Intermediate Data File + * int aperture : Target aperture (values are 1 to 8) + * int valid_spectrum: True if spectrum contains photons. + * long nout : number of tabulated points + * float wave_out : Output wavelength array + * float flux_out : Output flux array + * float var_out : Output variance array + * long counts_out : Output counts array (in counts) + * float weights_out : Output weights array (in counts) + * float bkgd_out : Output background array (in counts) + * short bpix_out : Output bad pixel spectrum + * char outrootname: Optional output file name + * + * Returns: 0 if successful + * + * HISTORY: 02/10/03 1.1 RDR started work + * 02/28/03 1.2 peb Added header files to file and tidied + * code using lint. + * 03/12/03 1.3 wvd Output ERROR = sqrt(var_out) + * 03/31/03 1.4 wvd Update keywords FILENAME, FILETYPE, + * and APER_ACT. + * 05/22/03 1.5 wvd Direct cf_error_init to stderr. + * 05/29/03 1.6 rdr Added bad pixel column + * 06/03/03 1.7 rdr Change naming convention to allow + * hist data + * 07/17/03 1.9 wvd Test var_out before taking sqrt. + * Change calfusettag.h to calfuse.h + * 10/01/03 1.10 wvd Modify verbose levels. + * 11/10/03 1.11 wvd Correct numbering scheme for HIRS + * and MDRS apertures. + * 02/13/04 1.12 wvd Correct error in COMMENT lines. + * 03/03/04 1.13 rdr Populate archive search keywords + * 03/05/04 1.14 wvd Change name of POTHOLE column + * to QUALITY. + * 03/24/04 1.15 wvd If valid_spectrum=FALSE, write + * warning message to file header. + * 04/06/04 1.16 bjg Include string.h and ctype.h + * 04/09/04 1.17 wvd If valid_spectrum=FALSE, set + * EXPTIME = 0 in file header. + * 04/27/04 1.18 wvd Move conversion from variance + * to sigma from this routine to + * cf_optimal_extraction. + * 06/11/04 1.19 peb Added the -r option to override the + * default rootname + * 02/01/05 1.20 wvd Revert to standard FITS binary + * table format for output file. + * 04/11/05 1.21 wvd In HIST mode, don't write SIA + * table to output spectral file. + * 06/03/05 1.22 wvd Return status from cf_copy_hist_header. + * 06/03/05 1.23 wvd Change cf_copy_hist_header to type void. + * 08/11/05 1.24 wvd Delete FITS_write_date from + * cf_copy_hist_header. + * + **************************************************************************/ + +#include +#include +#include +#include "calfuse.h" + +static char *ap_code[] = {"", "lif3", "lif2", "lif4", "lif1", + "sic3", "sic2", "sic4", "sic1"}; + +static void +cf_copy_hist_header(fitsfile *infits, fitsfile *outfits, int *status) +{ + char card[FLEN_CARD]; + int i, nkeys, naxis=0, nextend=1; + long naxes[2]; + + naxes[0] = naxes[1] = 0; + + FITS_create_img(outfits, SHORT_IMG, naxis, naxes, status); + FITS_delete_key(outfits, "COMMENT", status); + FITS_delete_key(outfits, "COMMENT", status); + FITS_write_key(outfits, TINT, "NEXTEND", &nextend, + "Number of standard extensions", status); + fits_get_hdrspace(infits, &nkeys, NULL, status); + cf_if_fits_error(*status); + for (i = 9; i <= nkeys; i++) { + FITS_read_record(infits, i, card, status); + FITS_write_record(outfits, card, status); + } +} + +int +cf_write_extracted_spectrum(fitsfile *infits, int aperture, + int valid_spectrum, long nout, float *wave_out, + float *flux_out, float *var_out, long *counts_out, + float *weights_out, float *bkgd_out, short *bpix_out, + char *outrootname) +{ + char CF_PRGM_ID[] = "cf_write_extracted_spectrum"; + char CF_VER_NUM[] = "1.24"; + + fitsfile *outfits; + int nextend=1, status=0, tfields=7, timeref; + long i, frow=1, felem=1; + float bw=0., center=0., wmin=1200., wmax=0. ; + char comment[FLEN_CARD], datestr[FLEN_CARD]; + char rootname[FLEN_VALUE]={'\0'}, instmode[FLEN_VALUE] ; + char det[FLEN_VALUE]={'\0'}, outfile[FLEN_VALUE]={'\0'}; + char extname[]="SPECTRUM"; + char *aperact[] = {"HIRS_LIF", "MDRS_LIF", "LWRS_LIF", "PINH_LIF", + "HIRS_SIC", "MDRS_SIC", "LWRS_SIC", "PINH_SIC"}; + char *ttype[]={"WAVE","FLUX","ERROR","COUNTS","WEIGHTS","BKGD","QUALITY"}; + char *tform[]={"1E", "1E", "1E", "1J", "1E", "1E", "1I"}; + char *tunit[]={"ANGSTROMS","ERG CM^-2 S^-1 ANG^-1","ERG CM^-2 S^-1 ANG^-1", + "COUNTS", "COUNTS", "COUNTS","UNITLESS"}; + + /* Initialize error checking */ + cf_error_init(CF_PRGM_ID, CF_VER_NUM, stderr); + + /* Enter a time stamp into the log */ + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Begin Processing"); + + /* + * Read the observation ID from the input file and create an + * output file name. + */ + FITS_movabs_hdu(infits, 1, NULL, &status); + FITS_read_key(infits, TSTRING, "ROOTNAME", rootname, NULL, &status); + FITS_read_key(infits, TSTRING, "DETECTOR", det, NULL, &status); + FITS_read_key(infits, TSTRING, "INSTMODE", instmode, NULL, &status); + + /* Override the default rootname if the -r option is given. */ + if (outrootname != NULL) + strcpy(rootname, outrootname); + + /* Convert detector name to lower case */ + det[1] = tolower(det[1]); + + if (!strncmp(instmode,"T",1)) + sprintf(outfile, "%11s%2s%4sttagfcal.fit", + rootname, det, ap_code[aperture]); + else if (!strncmp(instmode,"H",1)) + sprintf(outfile, "%11s%2s%4shistfcal.fit", + rootname, det, ap_code[aperture]); + else { + cf_if_error("Cannot create name for the output files.") ; + return 1; + } + cf_verbose(3, "Output file name = %s", outfile); + + /* Open the output file and copy the header info from the input file */ + FITS_create_file(&outfits, outfile, &status); + if (!strncmp(instmode,"T",1)) + FITS_copy_header(infits, outfits, &status); + else + cf_copy_hist_header(infits, outfits, &status); + FITS_update_key(outfits, TINT, "NEXTEND", &nextend, NULL, &status); + FITS_update_key(outfits, TSTRING, "FILENAME", outfile, NULL, &status); + FITS_update_key(outfits, TSTRING, "FILETYPE", + "CALIBRATED EXTRACTED SPECTRUM", NULL, &status); + FITS_update_key(outfits, TSTRING, "APER_ACT", aperact[aperture-1], + NULL, &status); + + /* If valid_spectrum = FALSE, write warning to file header. */ + if (valid_spectrum == FALSE) { + float exptime = 0.; + FITS_update_key(outfits, TFLOAT, "EXPTIME", &exptime, NULL, &status); + FITS_write_comment(outfits, " ", &status); + FITS_write_comment(outfits, + "No good data. Output arrays set to zero.", &status); + fits_get_system_time(datestr, &timeref, &status); + sprintf(comment, "CalFUSE v%s %.10s", CALFUSE_VERSION, datestr); + FITS_write_comment(outfits, comment, &status); + FITS_write_comment(outfits, " ", &status); + } + + /* Populate archive search keywords */ + for (i=0 ; i wmax) wmax=wave_out[i] ; + } + bw = wmax-wmin ; + center = (wmax + wmin) / 2. ; + FITS_update_key(outfits, TFLOAT, "BANDWID", &bw, NULL, &status); + FITS_update_key(outfits, TFLOAT, "CENTRWV", ¢er, NULL, &status); + FITS_update_key(outfits, TFLOAT, "WAVEMIN", &wmin, NULL, &status); + FITS_update_key(outfits, TFLOAT, "WAVEMAX", &wmax, NULL, &status); + + /* Put the data into the table */ + FITS_create_tbl(outfits, BINARY_TBL, nout, tfields, ttype, tform, + tunit, extname, &status); + FITS_write_col(outfits, TFLOAT, 1, frow, felem, nout, wave_out, &status); + FITS_write_col(outfits, TFLOAT, 2, frow, felem, nout, flux_out, &status); + FITS_write_col(outfits, TFLOAT, 3, frow, felem, nout, var_out, &status); + FITS_write_col(outfits, TLONG, 4, frow, felem, nout, counts_out, &status); + FITS_write_col(outfits, TFLOAT, 5, frow, felem, nout, weights_out, &status); + FITS_write_col(outfits, TFLOAT, 6, frow, felem, nout, bkgd_out, &status); + FITS_write_col(outfits, TSHORT, 7, frow, felem, nout, bpix_out, &status); + + /* Write some comments into the header */ + FITS_write_comment(outfits, " ", &status); + FITS_write_comment(outfits, "RAW COUNTS = COUNTS ", + &status); + FITS_write_comment(outfits, "TARGET COUNTS = WEIGHTS - BKGD ", + &status); + FITS_write_comment(outfits, "TARGET FLUX = TARGET COUNTS * HC / LAMBDA / " + "AEFF / EXPTIME / WPC", &status); + FITS_write_comment(outfits, " ", &status); + + FITS_close_file(outfits, &status); + + /* Enter a time stamp into the log */ + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Finished processing"); + + return (status); +} diff --git a/src/libcf/eclipse.c b/src/libcf/eclipse.c new file mode 100644 index 0000000..a1e0b44 --- /dev/null +++ b/src/libcf/eclipse.c @@ -0,0 +1,148 @@ +/***************************************************************************** + * Johns Hopkins University + * Center For Astrophysical Sciences + * FUSE + ***************************************************************************** + * + * Synopsis: int eclipse(double pos[3], double mjdate) + * + * Description: Determines if FUSE is in the day or night portion of the orbit. + * + * + * Arguments: double pos Cartesian vector xyz coord of satellite. + * double mjdate Julian date of observation + * + * Returns: int 0 if day portion of orbit + * 1 if night portion of orbit + * + * Calls: slaDcc2s dcc2s.f + * slaDranrm dranrm.f + * slaDsep dsep.f + * slaEvp evp.f + * slaPreces preces.f + * + * History: 03/10/98 E. Murphy Begin work. + * 03/10/98 E. Murphy Initial version working + * 07/07/99 E. Murphy Replaced x,y,z in call with pos + * 07/20/99 jm Removed duplicate define statements + * 08/26/99 E. Murphy ang_sep now returned. + * 05/31/00 peb Implemented cfortran.h calls for slalib + * functions. + * 12/18/03 bjg Change calfusettag.h to calfuse.h + * 06/17/04 bjg 1.4 Corrected cfortran call to sla_preces + * + * References: This routine makes use of the Starlink set of astronomical + * subroutines (SLALIB). More information can be found at + * http://star-www.rl.ac.uk. + ****************************************************************************/ + +#include +#include + +#ifdef CFORTRAN +#include "cfortran.h" +PROTOCCALLSFSUB3(SLA_DCC2S, sla_dcc2s, DOUBLEV, PDOUBLE, PDOUBLE) +#define slaDcc2s(V, A, B) \ + CCALLSFSUB3(SLA_DCC2S, sla_dcc2s, DOUBLEV, PDOUBLE, PDOUBLE, V, A, B) +PROTOCCALLSFFUN1(DOUBLE, SLA_DRANRM, sla_dranrm, DOUBLE) +#define slaDranrm(ANGLE) \ + CCALLSFFUN1(SLA_DRANRM, sla_dranrm, DOUBLE, ANGLE) +PROTOCCALLSFFUN4(DOUBLE, SLA_DSEP, sla_dsep, DOUBLE, DOUBLE, DOUBLE, \ + DOUBLE) +#define slaDsep(A1, B1, A2, B2) \ + CCALLSFFUN4(SLA_DSEP, sla_dsep, DOUBLE, DOUBLE, DOUBLE, DOUBLE, \ + A1, B1, A2, B2) +PROTOCCALLSFSUB6(SLA_EVP, sla_evp, DOUBLE, DOUBLE, DOUBLEV, DOUBLEV, \ + DOUBLEV, DOUBLEV) +#define slaEvp(DATE, DEQX, DVB, DPB, DVH, DPH) \ + CCALLSFSUB6(SLA_EVP, sla_evp, DOUBLE, DOUBLE, DOUBLEV, DOUBLEV, \ + DOUBLEV, DOUBLEV, DATE, DEQX, DVB, DPB, DVH, DPH) +PROTOCCALLSFSUB5(SLA_PRECES, sla_preces, STRING, DOUBLE, DOUBLE, PDOUBLE, \ + PDOUBLE) +#define slaPreces(SYSTEM, EP0, EP1, RA, DC) \ + CCALLSFSUB5(SLA_PRECES, sla_preces, STRING, DOUBLE, DOUBLE, PDOUBLE, \ + PDOUBLE, SYSTEM, EP0, EP1, RA, DC) +#else +#include "slalib.h" +#include "slamac.h" +#endif + +#include "calfuse.h" + +int eclipse(double *pos, double mjdate, double *ang_sep) +{ + /* Define variables. */ + int i, retcode; + double dvb[3], dpb[3], dvh[3], dph[3], epoch2; + double r, ra_earth, dec_earth, ra_sun, dec_sun, ang_earth, ang_sun; + char fk5_st[10]="FK5"; + + /* Calculate the J2000.0 apparent RA and DEC of the Earth */ + r=sqrt(pos[0]*pos[0]+pos[1]*pos[1]+pos[2]*pos[2]); + ra_earth=atan2(-pos[1],-pos[0]); + dec_earth=asin(-pos[2]/r); + + /* We must precess the J2000 RA and DEC to date of observation. This + * is a very small correction, and could probably be ignored. + */ + + epoch2=2000.0-((51544.0-mjdate)/365.25); + +#ifdef CFORTRAN + slaPreces(fk5_st, 2000.0, epoch2, ra_earth, dec_earth); +#else + slaPreces(fk5_st, 2000.0, epoch2, &ra_earth, &dec_earth); +#endif + + /* Evp returns four 3-vectors containing the barycentric velocity and + * position (dvb,dpv) and the heliocentric velocity and position + * (dvh,dph) of the Earth on the date mjdate. It requires a modified + * Julian date as input. Output has units of AU for positions and + * AU/s for velocities. + */ + + slaEvp(mjdate, 2000.0, dvb, dpb, dvh, dph); + + /* Convert the 3-vector position of the Sun into a J2000.0 RA and DEC */ + + for (i=0; i<3; i++) dph[i]*=-1.0; + + +#ifdef CFORTRAN + slaDcc2s(dph, ra_sun, dec_sun); +#else + slaDcc2s(dph, &ra_sun, &dec_sun); +#endif + + ra_sun=slaDranrm(ra_sun); + + /* We must precess the J2000 RA and DEC to date of observation. This + * is a very small correction, and could probably be ignored. + */ + + epoch2=2000.0-((51544.0-mjdate)/365.25); + +#ifdef CFORTRAN + slaPreces(fk5_st, 2000.0, epoch2, ra_sun, dec_sun); +#else + slaPreces(fk5_st, 2000.0, epoch2, &ra_sun, &dec_sun); +#endif + + /* Compute the angular sizes of the Earth and the Sun. */ + + ang_earth=asin(RE/r); + + ang_sun=asin(RS/(sqrt(dph[0]*dph[0]+dph[1]*dph[1]+dph[2]*dph[2])*AU)); + + /* Compute the angular separation of the Earth and the Sun. */ + + *ang_sep=slaDsep(ra_earth, dec_earth, ra_sun, dec_sun); + + retcode=0; + if (*ang_sep < ang_earth+ang_sun) retcode=1; + + /* Convert ang_sep into degrees. */ + *ang_sep /= RADIAN; + + return retcode; +} diff --git a/src/libcf/geod_mag.c b/src/libcf/geod_mag.c new file mode 100644 index 0000000..6750f9d --- /dev/null +++ b/src/libcf/geod_mag.c @@ -0,0 +1,40 @@ +/***************************************************************************** + * Johns Hopkins University + * Center For Astrophysical Sciences + * FUSE + ***************************************************************************** + * + * Synopsis: double geod_mag(double lon, double lat) + * + * Description: Computes the magnetic latitude of FUSE from the + * given geocentric longitude and latitude. + * + * Arguments: double lon,lat (deg) Geocentric longitude and latitude + * + * Returns: double Geomagnetic latitude. + * + * History: 03/11/98 E. Murphy Begin work. + * 03/11/98 E. Murphy Initial version working + * 04/13/99 E. Murphy Moved PI and RADIAN to calfuse.h + * 12/18/03 bjg Change calfusettag.h to calfuse.h + * + * Ake, T. 1998 in The Scientific Impact of the Goddard + * High Resolution Spectrograph, ed. J. C. Brandt et al., + * ASP Conference Series, in preparation. + ****************************************************************************/ + +#include +#include +#include "calfuse.h" + +double geod_mag(double lon, double lat) +{ + double lat_rad, c1; + + lat_rad=lat*RADIAN; + + c1=sin(lat_rad)*cos(11.4*RADIAN)- + cos(lat_rad)*cos((lon+69.8)*RADIAN)*sin(11.4*RADIAN); + + return asin(c1)/RADIAN; +} diff --git a/src/libcf/helio_vel.c b/src/libcf/helio_vel.c new file mode 100644 index 0000000..bc069b6 --- /dev/null +++ b/src/libcf/helio_vel.c @@ -0,0 +1,82 @@ +/***************************************************************************** + * Johns Hopkins University + * Center For Astrophysical Sciences + * FUSE + ***************************************************************************** + * + * Synopsis: double helio_vel(double mjdate, double ra, double dec) + * + * Description: Computes the Earth's orbital velocity in the direction + * of ra,dec to convert to heliocentric velocity. + * + * Arguments: double mjdate Mod. Julian date of observation + * double ra (deg) J2000.0 right ascension + * double dec (deg) J2000.0 declination + * + * Returns: double (km/s) velocity in direction of source + * + * Calls: slaEvp evp.f + * slaDcs2c dcs2c.f + * slaDvdv dvdv.f + * + * History: 03/05/98 E. Murphy Begin work. + * 03/05/98 E. Murphy Initial version working + * 05/31/00 peb Implemented cfortran.h calls for slalib + * functions. + * 06/15/01 V. Dixon Correct sign of return value to agree + * with astronomical convention. + * 12/18/03 bjg Change calfusettag.h to calfuse.h + * + * References: This routine makes use of the Starlink set of astronomical + * subroutines (SLALIB). More information can be found at + * http://star-www.rl.ac.uk. + ****************************************************************************/ + +#include + +#ifdef CFORTRAN +#include "cfortran.h" + +PROTOCCALLSFSUB3(SLA_DCS2C, sla_dcs2c, DOUBLE, DOUBLE, DOUBLEV) +#define slaDcs2c(A, B, V) \ + CCALLSFSUB3(SLA_DCS2C, sla_dcs2c, DOUBLE, DOUBLE, DOUBLEV, A, B, V) + +PROTOCCALLSFFUN2(DOUBLE, SLA_DVDV, sla_dvdv, DOUBLEV, DOUBLEV) +#define slaDvdv(VA, VB) \ + CCALLSFFUN2(SLA_DVDV, sla_dvdv, DOUBLEV, DOUBLEV, VA, VB) + +PROTOCCALLSFSUB6(SLA_EVP, sla_evp, DOUBLE, DOUBLE, DOUBLEV, DOUBLEV, \ + DOUBLEV, DOUBLEV) +#define slaEvp(DATE, DEQX, DVB, DPB, DVH, DPH) \ + CCALLSFSUB6(SLA_EVP, sla_evp, DOUBLE, DOUBLE, DOUBLEV, DOUBLEV, \ + DOUBLEV, DOUBLEV, DATE, DEQX, DVB, DPB, DVH, DPH) +#else +#include "slalib.h" +#include "slamac.h" +#endif + +#include "calfuse.h" + +double helio_vel(double mjdate, double ra, double dec) +{ + /* Define variables. */ + double dvb[3], dpb[3], dvh[3], dph[3], vect[3]; + /* + * Evp returns four 3-vectors containing the barycentric velocity and + * position (dvb,dpb) and the heliocentric velocity and position + * (dvh,dph) of the Earth on the date mjdate. It requires a modified + * Julian date as input. Output has units of AU for positions and + * AU/s for velocities. + */ + slaEvp(mjdate, 2000.0, dvb, dpb, dvh, dph); + + /* Convert the J2000.0 RA and DEC into a 3-vector position */ + + slaDcs2c(RADIAN*ra, RADIAN*dec, vect); + /* + * Compute the dot product of the RA DEC position vector and the + * heliocentric velocity vector. Mutliply by km/AU to get velocity + * in km/s. + */ + return slaDvdv(vect, dvh)*149.5978707E6; +} diff --git a/src/libcf/lsrd_vel.c b/src/libcf/lsrd_vel.c new file mode 100644 index 0000000..a90c22b --- /dev/null +++ b/src/libcf/lsrd_vel.c @@ -0,0 +1,51 @@ +/***************************************************************************** + * Johns Hopkins University + * Center For Astrophysical Sciences + * FUSE + ***************************************************************************** + * + * Synopsis: double lsrd_vel(double ra, double dec) + * + * Description: Computes the Sun's velocity in the direction + * of ra,dec to convert to a LSR. In this case we + * are using the dynamical solar motion of + * 16.6 km/s towards l=53, b=+25. + * + * Arguments: double ra (deg) J2000.0 right ascension + * double dec (deg) J2000.0 declination + * + * Returns: double (km/s) velocity in direction of source + * + * Calls: slaRvlsrd rvslrd.f + * + * History: 03/05/98 E. Murphy Begin work. + * 03/05/98 E. Murphy Initial version working + * 05/31/00 peb Implemented cfortran.h calls for slalib + * functions. + * 06/15/01 V. Dixon Multiply return value by -1.0 to agree + * with astronomical convention. + * 12/18/03 bjg Change calfusettag.h to calfuse.h + * + * References: This routine makes use of the Starlink set of astronomical + * subroutines (SLALIB). More information can be found at + * http://star-www.rl.ac.uk. + ****************************************************************************/ + +#include + +#ifdef CFORTRAN +#include "cfortran.h" +PROTOCCALLSFFUN2(FLOAT, SLA_RVLSRD, sla_rvlsrd, FLOAT, FLOAT) +#define slaRvlsrd(R2000, D2000) \ + CCALLSFFUN2(SLA_RVLSRD, sla_rvlsrd, FLOAT, FLOAT, R2000, D2000) +#else +#include "slalib.h" +#include "slamac.h" +#endif + +#include "calfuse.h" + +double lsrd_vel(double ra, double dec) +{ + return -1.0 * slaRvlsrd((float) ra*RADIAN, (float) dec*RADIAN); +} diff --git a/src/libcf/lsrk_vel.c b/src/libcf/lsrk_vel.c new file mode 100644 index 0000000..15f5a6c --- /dev/null +++ b/src/libcf/lsrk_vel.c @@ -0,0 +1,52 @@ +/**************************************************************************** + * Johns Hopkins University + * Center For Astrophysical Sciences + * FUSE + **************************************************************************** + * + * Synopsis: double lsrk_vel(double ra, double dec) + * + * Description: Computes the Sun's velocity in the direction + * of ra,dec to convert to a LSR. In this case we + * are using standard solar motion of + * 20 km/s towards RA 18h Dec +30d (1900). + * + * Arguments: double ra (deg) J2000.0 right ascension + * double dec (deg) J2000.0 declination + * + * Returns: double (km/s) velocity in direction of source + * + * Calls: slaRvlsrk rvlsrk.f + * + * History: 03/05/98 E. Murphy Begin work. + * 03/05/98 E. Murphy Initial version working + * 04/13/99 E. Murphy Clean up a bit + * 05/31/00 peb Implemented cfortran.h calls for slalib + * functions. + * 06/15/01 V. Dixon Multiply return value by -1.0 to agree + * with astronomical convention. + * 12/18/03 bjg Change calfusettag.h to calfuse.h + * + * References: This routine makes use of the Starlink set of astronomical + * subroutines (SLALIB). More information can be found at + * http://star-www.rl.ac.uk. + ****************************************************************************/ + +#include + +#ifdef CFORTRAN +#include "cfortran.h" +PROTOCCALLSFFUN2(FLOAT, SLA_RVLSRK, sla_rvlsrk, FLOAT, FLOAT) +#define slaRvlsrk(R2000, D2000) \ + CCALLSFFUN2(SLA_RVLSRK, sla_rvlsrK, FLOAT, FLOAT, R2000, D2000) +#else +#include "slalib.h" +#include "slamac.h" +#endif + +#include "calfuse.h" + +double lsrk_vel(double ra, double dec) +{ + return -1.0 * slaRvlsrk((float) ra*RADIAN, (float) dec*RADIAN); +} diff --git a/src/libcf/month_day.c b/src/libcf/month_day.c new file mode 100644 index 0000000..1ecfae1 --- /dev/null +++ b/src/libcf/month_day.c @@ -0,0 +1,19 @@ +/* month_day: return month,day from day of year */ +/* 07/21/04 1.4 wvd Add () to defn of leap */ + +#include "calfuse.h" + +void month_day(int year, int yearday, int *pmonth, int *pday) +{ + static char daytab[2][13]={ + {0,31,28,31,30,31,30,31,31,30,31,30,31}, + {0,31,29,31,30,31,30,31,31,30,31,30,31} + }; + int i, leap; + + leap = ((year%4 == 0 && year%100 != 0) || year%400 == 0); + for (i=1; yearday>daytab[leap][i]; i++) + yearday-=daytab[leap][i]; + *pmonth=i; + *pday=yearday; +} diff --git a/src/libcf/pole_ang.c b/src/libcf/pole_ang.c new file mode 100644 index 0000000..ae90cc2 --- /dev/null +++ b/src/libcf/pole_ang.c @@ -0,0 +1,64 @@ +/***************************************************************************** + * Johns Hopkins University + * Center For Astrophysical Sciences + * FUSE + ***************************************************************************** + * + * Synopsis: double pole_ang(double *pos, double *vel, double ra, double dec) + * + * Description: Computes the position of the orbit pole from the given state + * 6-vector. Returns the angle between the pole and the given + * RA and DEC. + * + * Arguments: double *pos (km) 3-vector position of satellite + * double *vel (km/s) 3-vector velocity of satellite + * double ra,dec (deg) position of source + * + * Returns: double (deg) angle from orbit pole to source + * + * History: 07/06/06 wvd 1.1 Adapted from space_vel and sun_ang + * 04/08/07 wvd 1.2 Cast SGP4_getPole as a void. + * + * References: This routine makes use of the Starlink set of astronomical + * subroutines (SLALIB). More information can be found at + * http://star-www.rl.ac.uk. + *****************************************************************************/ + +#include + +#ifdef CFORTRAN +#include "cfortran.h" +PROTOCCALLSFSUB3(SLA_DCC2S, sla_dcc2s, DOUBLEV, PDOUBLE, PDOUBLE) +#define slaDcc2s(V, A, B) \ + CCALLSFSUB3(SLA_DCC2S, sla_dcc2s, DOUBLEV, PDOUBLE, PDOUBLE, V, A, B) +PROTOCCALLSFFUN1(DOUBLE, SLA_DRANRM, sla_dranrm, DOUBLE) +#define slaDranrm(ANGLE) \ + CCALLSFFUN1(SLA_DRANRM, sla_dranrm, DOUBLE, ANGLE) +PROTOCCALLSFFUN4(DOUBLE, SLA_DSEP, sla_dsep, DOUBLE, DOUBLE, DOUBLE, DOUBLE) +#define slaDsep(A1, B1, A2, B2) \ + CCALLSFFUN4(SLA_DSEP, sla_dsep, DOUBLE, DOUBLE, DOUBLE, DOUBLE, \ + A1, B1, A2, B2) +#else +#include "slalib.h" +#include "slamac.h" +#endif + +#include "calfuse.h" + +double pole_ang(double pos[3], double vel[3], double ra, double dec) +{ + double pole[3], ra_pole, dec_pole; + + /* Get 3-vector containing the orbit pole. */ + (void) SGP4_getPole(pos, vel, pole); + + /* Convert 3-vector into J2000.0 RA and DEC */ +#ifdef CFORTRAN + slaDcc2s(pole, ra_pole, dec_pole); +#else + slaDcc2s(pole, &ra_pole, &dec_pole); +#endif + + /* Compute the angular separation of RA, DEC and RA_POLE, DEC_POLE */ + return slaDsep(ra*RADIAN, dec*RADIAN, slaDranrm(ra_pole), dec_pole)/RADIAN; +} diff --git a/src/libcf/read_tle.c b/src/libcf/read_tle.c new file mode 100644 index 0000000..38db069 --- /dev/null +++ b/src/libcf/read_tle.c @@ -0,0 +1,303 @@ +/****************************************************************************** + * Johns Hopkins University + * Center For Astrophysical Sciences + * FUSE + ****************************************************************************** + * + * Synopsis: read_tle(fitsfile *fptr) + * + * Description: read_tle will read the standard tle format file FUSE.TLE + * and place the orbital elements into the header of the + * fitsfile. The FUSE.TLE file will contain multiple orbital + * element sets, so the set closest in time to the observation + * will be used. + * + * Arguments: fitsfile *fptr Pointer to input file + * + * History: 11/11/98 emurphy Begin work. + * 03/18/98 emurphy Added To do list. + * 04/08/99 peb Tidied code and added necessary + * include files + * 06/07/99 peb Added reporting of version control. + * 06/22/99 peb Added FITS_ wrappers. + * 08/05/99 emm Added statements to print date + * of obs and TLE if dtime > 5. + * Also modified program to work with + * FES keywords TEXPSTRT and TEXPEND + * 05/31/00 peb Implemented cfortran.h calls for slalib + * functions. + * 02/13/03 v1.4 wvd Change 0 to NULL in FITS_update_key + * 03/01/03 v1.5 wvd Correct use of pointer in FITS_read_key + * 04/01/03 v1.6 wvd Replace cf_errmsg with cf_if_warning, + * printf with cf_verbose + * 12/18/03 v1.7 bjg Change calfusettag.h to calfuse.h + * 04/07/07 v1.8 wvd Initialize min_mjd to zero to silence + * compiler warnings. + * + *****************************************************************************/ + +#include +#include +#include +#include + +#ifdef CFORTRAN +#include "cfortran.h" +PROTOCCALLSFSUB5(SLA_CLDJ, sla_cldj, INT, INT, INT, PDOUBLE, PINT) +#define slaCldj(IY, IM, ID, DJM, J) \ + CCALLSFSUB5(SLA_CLDJ, sla_cldj, INT, INT, INT, PDOUBLE, PINT, \ + IY, IM, ID, DJM, J) +#else +#include "slalib.h" +#include "slamac.h" +#endif + +#include "calfuse.h" + +#define MAXCHARS 120 +static char CF_PRGM_ID[] = "read_tle"; +static char CF_VER_NUM[] = "1.8"; + +void read_tle(fitsfile *fptr) +{ + char line1[MAXCHARS], line2[MAXCHARS], line3[MAXCHARS]; + char sat_num[10], security_class[10], international_num[10]; + char inchar[15][15], sp[15][2], sgn[4][2]; + char comment[FLEN_CARD], eccen_str[20]; + char n6_mant_str[20], drag_mant_str[20], instrument[FLEN_CARD]; + int status=0, hdutype=0, card_num, epoch_year, n6_exponent; + int drag_exponent, ephemeris, elset_num, checksum1, checksum2; + int rev_num, e_month, e_day; + double n6_mantissa, drag_mantissa, epoch_day, n2, inclin, raan; + double aop, mean_anom, mean_mot, n6, drag, semimaj, revspersec; + double expstart, expend, expmiddle, eccentr, dtime=1.0e9; + double i_day, f_day, mjd, mjd_f, mjd_d, min_mjd=0; + FILE *ftle; + + /* Enter a timestamp into the log. */ + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Begin reading TLE file"); + + /* Open the file with the standard two-line elements. */ + ftle = NULL; + ftle = fopen(cf_cal_file("FUSE.TLE"),"r"); + if (ftle == NULL) + cf_if_error("Cannot find file FUSE.TLE, which contains the" + " orbital elements."); + + /* Rewind the fits file and get the start time of the exposure */ + FITS_movabs_hdu(fptr, 1, &hdutype, &status); + FITS_read_key(fptr, TSTRING, "INSTRUME", instrument, comment, &status); + + /* In the primary header, the FES files use keywords with a different + name. This is because the FES may have many exposures in a file. + The TEXPSTRT is the start of the first exposure and TEXPEND is the + end of the last exposure. */ + if (!strncmp(instrument,"FES",3)) { + /* Read in FES keywords */ + FITS_read_key(fptr, TDOUBLE, "TEXPSTRT", &expstart, comment, &status); + FITS_read_key(fptr, TDOUBLE, "TEXPEND", &expend, comment, &status); + } else { + /* Read in FUV keywords */ + FITS_read_key(fptr, TDOUBLE, "EXPSTART", &expstart, comment, &status); + FITS_read_key(fptr, TDOUBLE, "EXPEND", &expend, comment, &status); + } + + /* expmiddle is in mjd */ + expmiddle = (expstart+expend)/2.0; + + /* Read in FUSE.TLE file by getting one line at a time */ + while (fgets(line1, MAXCHARS,ftle) != NULL) { + fgets(line2, MAXCHARS, ftle); + fgets(line3, MAXCHARS, ftle); + +#ifdef DEBUG + printf("\n\n%-80.80s\n",line1); + printf("%-80.80s\n",line2); + printf("%-80.80s\n",line3); +#endif + /* + * This may look like a stupid way to do this, but it has to be + * done this way. You see, the fields can contain leading blanks + * which should be interpreted as zeros. However, c skips over + * leading blanks when reading %f and %d. + */ + sscanf(line2,"%1c%1c%5c%1c%1c%8c%1c%2c%12c%1c%1c%9c%1c%1c%5c%2c%1c" + "%1c%5c%2c%1c%1c%1c%4c%1c", + inchar[1],sp[1],inchar[2],inchar[3],sp[2],inchar[4],sp[3], + inchar[5],inchar[6],sp[4],sgn[1],inchar[7],sp[5],sgn[2], + inchar[8],inchar[9],sp[6],sgn[3],inchar[10],inchar[11], + sp[7],inchar[12], sp[8],inchar[13],inchar[14]); + + inchar[1][1]='\0'; + card_num=atoi(inchar[1]); + + inchar[2][5]='\0'; + strncpy(sat_num,inchar[2],5); + + inchar[3][1]='\0'; + strncpy(security_class,inchar[3],1); + + inchar[4][8]='\0'; + strncpy(international_num,inchar[4],8); + + inchar[5][2]='\0'; + epoch_year=atoi(inchar[5]); + if (epoch_year < 50) + epoch_year+=2000; + else + epoch_year+=1900; + + inchar[6][12]='\0'; + epoch_day=atof(inchar[6]); + + inchar[7][9]='\0'; + n2=atof(inchar[7]); + if (sgn[1][0] == '-') + n2*=-1.0; + + inchar[8][5]='\0'; + strcpy(n6_mant_str,"0."); + strncat(n6_mant_str,inchar[8],7); +#ifdef DEBUG + printf("n6=%-10.10s\n",n6_mant_str); +#endif + n6_mantissa=atof(n6_mant_str); + if (sgn[2][0] == '-') + n6_mantissa*=-1.0; + + inchar[9][2]='\0'; + n6_exponent=atoi(inchar[9]); + + inchar[10][5]='\0'; + strcpy(drag_mant_str,"0."); + strncat(drag_mant_str,inchar[10],7); +#ifdef DEBUG + printf("Drag=%-10.10s\n",drag_mant_str); +#endif + drag_mantissa=atof(drag_mant_str); + if (sgn[3][0] == '-') + drag_mantissa*=-1.0; + + inchar[11][2]='\0'; + drag_exponent=atoi(inchar[11]); + + inchar[12][1]='\0'; + ephemeris=atoi(inchar[12]); + + inchar[13][4]='\0'; + elset_num=atoi(inchar[13]); + + inchar[14][1]='\0'; + checksum1=atoi(inchar[14]); + + n6=n6_mantissa*pow(10.0,(double) n6_exponent); + drag=drag_mantissa*pow(10.0,(double) drag_exponent); + +#ifdef DEBUG + printf("n6=>%10.5f %5d %15.6E\n", n6_mantissa, n6_exponent, n6); + printf("drag=>%10.5f %5d %15.6E\n", drag_mantissa, + drag_exponent, drag); + for(i=1; i<=14; i++) + printf("%2d %-15.15s\n",i,inchar[i]); + for(i=1; i<=3; i++) + printf("%2d %-5.5s\n",i,sgn[i]); +#endif + sscanf(line3,"%1c%1c%5c%1c%8c%1c%8c%1c%7c%1c%8c%1c%8c%1c%11c%5c%1c", + inchar[1],sp[1],inchar[2],sp[2],inchar[3],sp[3],inchar[4], + sp[4],inchar[5],sp[5],inchar[6],sp[6],inchar[7],sp[7], + inchar[8],inchar[9],inchar[10]); + inchar[1][1]='\0'; + card_num=atoi(inchar[1]); + + inchar[2][5]='\0'; + strncpy(sat_num,inchar[2],5); + + inchar[3][8]='\0'; + inclin=atof(inchar[3]); + + inchar[4][8]='\0'; + raan=atof(inchar[4]); + + inchar[5][7]='\0'; + /* + * strcpy(eccen_str,"0."); + * strncat(eccen_str,inchar[5],8); + */ + sprintf(eccen_str,"0.%-8s",inchar[5]); +#ifdef DEBUG + printf("Ecstr=%-20.20s\n",eccen_str); +#endif + eccentr=atof(eccen_str); + + inchar[6][8]='\0'; + aop=atof(inchar[6]); + + inchar[7][8]='\0'; + mean_anom=atof(inchar[7]); + + inchar[8][11]='\0'; + mean_mot=atof(inchar[8]); + + inchar[9][5]='\0'; + rev_num=atof(inchar[9]); + + inchar[10][1]='\0'; + checksum2=atoi(inchar[10]); + +#ifdef DEBUG + for(i=1; i<=10; i++) + printf("%2d %-15.15s\n",i,inchar[i]); + printf("%4d\n%12.8f\n%10.8f\n%10.5E\n%10.5E%5d%5d%5d\n", + epoch_year, epoch_day, n2, n6, drag, ephemeris, + elset_num, checksum1); + printf("\n%8.4f\n%8.4f\n%10.8f\n%8.4f\n%8.4f\n%11.8f\n%5d\n%1d\n", + inclin, raan, (float) eccentr, aop, mean_anom, + mean_mot, rev_num, checksum2); +#endif + /* Convert the year and day of year into a year month day */ + + f_day = modf(epoch_day, &i_day); + + month_day(epoch_year, (int) i_day, &e_month, &e_day); + + /* Convert year month day into a Julian date. */ +#ifdef CFORTRAN + slaCldj(epoch_year, e_month, e_day, mjd, status); +#else + slaCldj(epoch_year, e_month, e_day, &mjd, &status); +#endif + + mjd += f_day; + + if (fabs(expmiddle-mjd) < dtime) { + dtime = fabs(expmiddle-mjd); + min_mjd=mjd; + revspersec = mean_mot/(24.0*60.0*60.0); + semimaj = pow(MU/(4.0*PI*PI*revspersec*revspersec),1.0/3.0); + mjd_f=modf(mjd, &mjd_d); + FITS_update_key(fptr, TDOUBLE, "EPCHTIMD", &mjd_d, NULL, &status); + FITS_update_key(fptr, TDOUBLE, "EPCHTIMF", &mjd_f, NULL, &status); + FITS_update_key(fptr, TDOUBLE, "INCLINAT", &inclin, NULL, &status); + FITS_update_key(fptr, TDOUBLE, "ECCENTRY", &eccentr, NULL, &status); + FITS_update_key(fptr, TDOUBLE, "MEANANOM", &mean_anom, NULL,&status); + FITS_update_key(fptr, TDOUBLE, "ARGPERIG", &aop, NULL, &status); + FITS_update_key(fptr, TDOUBLE, "RASCASCN", &raan, NULL, &status); + FITS_update_key(fptr, TDOUBLE, "SEMIMAJR", &semimaj, NULL, &status); + FITS_update_key(fptr, TDOUBLE, "MEANMOTN", &mean_mot, NULL, &status); + FITS_update_key(fptr, TDOUBLE, "FDM2COEF", &n2, NULL, &status); + FITS_update_key(fptr, TDOUBLE, "SDM6COEF", &n6, NULL, &status); + FITS_update_key(fptr, TDOUBLE, "DRAGCOEF", &drag, NULL, &status); + FITS_update_key(fptr, TSTRING, "PROPMODL", "SGP4", NULL, &status); + } + } /* endwhile */ + + if (dtime > 5.0) { + cf_verbose(2, "MJD OBS=%12.5f MJD TLE=%12.5f DT=%12.5f\n", + expmiddle, min_mjd, dtime); + cf_if_warning("Orbital elements are more than 5 days old."); + } + + /* Enter a timestamp into the log. */ + cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Done reading TLE file"); +} + diff --git a/src/libcf/saa.c b/src/libcf/saa.c new file mode 100644 index 0000000..0d2d0e3 --- /dev/null +++ b/src/libcf/saa.c @@ -0,0 +1,74 @@ +/***************************************************************************** + * Johns Hopkins University + * Center For Astrophysical Sciences + * FUSE + ***************************************************************************** + * + * Synopsis: int saa(saareg *saa, double lon, double lat) + * + * Description: Determines if FUSE is in the SAA for given models of the SAA + * + * + * Arguments: saareg *saa A structure containing data that roughly + * outlines the SAA region. + * (n_points: number of points + * lat: the latitude array + * lon: the longitude array) + * (currently we have only one model). + * double lon,lat Geocentric longitude and latitude of FUSE + * + * Returns: int 0 if not in SAA + * 1 if in SAA + * + * History: 07/17/98 E. Murphy Begin work. + * 06/22/99 peb Tidied code, added FITS_ wrappers, + * removed hardcoded variables. + * 07/02/99 peb Moved SAA data to a structure. + * 08/25/99 emm Fixed bug in setting maxlon + * 08/28/03 v1.3 bjg Adopt Bryce's algorithm for determining + * when FUSE is in the SAA. + * 08/28/03 v1.4 bjg v1.3 didn't compile but v1.4 does + * 08/29/03 v1.5 bjg slightly modified getDir + * + ****************************************************************************/ + +#include "calfuse.h" + +int getDir(double lon0,double lat0,double lon1,double lat1,double lon2,double lat2) +{ + +double dx1, dx2, dy1, dy2, t1, t2; + + dx1=lon1-lon0; dy1=lat1-lat0; + dx2=lon2-lon0; dy2=lat2-lat0; + + t1=dx1*dy2; t2=dy1*dx2; + + if (t1>t2) + return(-1); + if (t1n_points-1; i++) { + dir=getDir(lon,lat,(double)(saa->lon[i]),(double)(saa->lat[i]),(double)(saa->lon[i+1]),(double)(saa->lat[i+1])); + if (dir*oldDir<0) + return(0); + else + oldDir=dir; + } + + return(1); +} diff --git a/src/libcf/set_orbit_parms.c b/src/libcf/set_orbit_parms.c new file mode 100644 index 0000000..65baca6 --- /dev/null +++ b/src/libcf/set_orbit_parms.c @@ -0,0 +1,86 @@ +/***************************************************************************** + * Johns Hopkins University + * Center For Astrophysical Sciences + * FUSE + ***************************************************************************** + * + * Synopsis: SGP4 set_orbit_parms(fitsfile *infits) + * + * Description: Initialized the sgp4 structure and reads the orbital + * paramaters from the infits header and places the data + * in the sgp4 structure. It also calculates a number of + * time invariant quantities in the sgp4 structure. + * + * Arguments: fitsfile *infits Input FITS file. + * + * Return: SGP4 sgp4 Structure with orb parms. + * + * History: 07/07/99 emurphy Begin and finished work + * 07/14/99 emurphy Fixed minor bugs + * 07/21/99 peb Changed function to return SGP4 + * pointer. (This fixes a bug.) + * 08/05/99 emurphy Converted to use set_orbit_parms_calc + * so that FES pipeline can use these + * routines. + * 12/18/03 bjg Change calfusettag.h to calfuse.h + * 04/07/07 1.4 wvd Delete CF_PRGM_ID and CF_VER_NUM, + * as they are not used. + * + ****************************************************************************/ + +#include +#include "calfuse.h" +#include "sgp4.h" + +SGP4 set_orbit_parms_calc(fitsfile *infits) +{ + int status=0; + char comment[FLEN_CARD]; + double epchtime, td, tf, inclinat, eccentry, meananom, argperig, rascascn; + double n0dt, n0dt2, bstar, mean_motion; + SGP4 sgp4; + + /* Get the orbital data from the header of the infits file. */ + FITS_read_key(infits, TDOUBLE, "EPCHTIMD", &td, comment, &status); + FITS_read_key(infits, TDOUBLE, "EPCHTIMF", &tf, comment, &status); + epchtime=td+tf; + FITS_read_key(infits, TDOUBLE, "INCLINAT", &inclinat, comment, &status); + FITS_read_key(infits, TDOUBLE, "ECCENTRY", &eccentry, comment, &status); + FITS_read_key(infits, TDOUBLE, "MEANANOM", &meananom, comment, &status); + FITS_read_key(infits, TDOUBLE, "ARGPERIG", &argperig, comment, &status); + FITS_read_key(infits, TDOUBLE, "RASCASCN", &rascascn, comment, &status); + FITS_read_key(infits, TDOUBLE, "FDM2COEF", &n0dt, comment, &status); + FITS_read_key(infits, TDOUBLE, "SDM6COEF", &n0dt2, comment, &status); + FITS_read_key(infits, TDOUBLE, "DRAGCOEF", &bstar, comment, &status); + FITS_read_key(infits, TDOUBLE, "MEANMOTN", &mean_motion, comment, &status); + + sgp4 = SGP4_create(); + + SGP4_set(sgp4, epchtime, n0dt, n0dt2, bstar, inclinat, + rascascn, eccentry, argperig, meananom, mean_motion); + + /* do time invariant initializations */ + SGP4_init(sgp4); + return sgp4; +} + +SGP4 set_orbit_parms(fitsfile *infits) +{ + int status=0, hdunum=0, hdutype; + SGP4 sgp4; + /* + * The infits file pointer may be down in one of the extensions + * whereas the orbital info is in the primary hdu. Therefore, + * record the current position, move to the primary header, + * set the orbital data, and return to the previous hdu. + */ + FITS_get_hdu_num(infits, &hdunum); + FITS_movabs_hdu(infits, 1, &hdutype, &status); + + sgp4=set_orbit_parms_calc(infits); + + FITS_movabs_hdu(infits, hdunum, &hdutype, &status); + + return sgp4; + +} diff --git a/src/libcf/sgp4.c b/src/libcf/sgp4.c new file mode 100644 index 0000000..b14dc45 --- /dev/null +++ b/src/libcf/sgp4.c @@ -0,0 +1,426 @@ +/* H+ + * Title : sgp4.c + * Author : Bryce A. Roberts + * Date : 23 February 1999 + * Synopsis : implementation of SGP4 propagation routines + * SCCS : @(#)sgp4.c 1.6 05/14/00 + * Revisions : + * mm/dd/yy name description + * 01/14/00 ma get rid of unused function get_time (May 14 2000) + * 12/18/03 bjg Change calfusettag.h to calfuse.h +* H- + */ + +#include +#include +#include "calfuse.h" +#include "sgp4.h" + +/* define some absolute constants used by SGP4 */ +#define MIN_PER_DAY (1440.0) +#define KM_PER_EARTH (6378.135) +#define TWOBYTHREE (2.0/3.0) +#define Q0 (120.0) +#define S0 (78.0) +#define THREEPIBYTWO (PIBY2*3.0) +#define KE (0.074366916) +#define AE (1.0) +#define S (AE*(1.0+S0/KM_PER_EARTH)) +#define Q0MS4 pow((Q0-S0)*AE/KM_PER_EARTH, 4) +#define CK2 (0.5*J2*AE*AE) +#define CK4 (-0.375*J4*AE*AE*AE*AE) +#define A30 (-J3/AE*AE*AE) + +#ifndef J2 +#define J2 (1.082616E-3) +#endif + +#ifndef J3 +#define J3 (-0.253881E-5) +#endif + +#ifndef J4 +#define J4 (-1.65597E-6) +#endif + +#ifndef PI +#define PI (3.141592653589793) +#endif + +#ifndef TWOPI +#define TWOPI (2.0*PI) +#endif + +#define RAD2DEG(x) (((x)*180.0)/PI) +#define DEG2RAD(x) ((PI/180.0)*(x)) + +#ifndef false +#define false (0) +#endif + +#ifndef true +#define true (1) +#endif + + +/* + * Name: SGP4_isLeap + * Purpose: determine if a given year is a leap year + * Input: int year (e.g. 1999) + * Output: returns 1 if leap year, 0 if not + */ +static int SGP4_isLeap(int year) { + return(((year%4==0 && year%100!=0) || year%400==0)); + } + + +/* + * Name: SGP4_doy2cal + * Purpose: convert year/day-of-year to Gregorian calendar month and day + * Input: int year, doy + * Output: int *month, int *day, returns 0 for fail, 1 for success + */ +static int SGP4_doy2cal(int year, int doy, int *month, int *day) { + /* number of days in leap and non-leap year months */ + static int daytab[2][13]={{0,31,28,31,30,31,30,31,31,30,31,30,31}, + {0,31,29,31,30,31,30,31,31,30,31,30,31}}; + int leap; + + /* do range checking */ + if (doy<1 || doy>366) + return(false); + + leap=SGP4_isLeap(year) ? 1 : 0; + *day=doy; + for (*month=1; *day>daytab[leap][*month]; (*month)++) + *day-=daytab[leap][*month]; + + return(true); + } + + +/* + * Name: SGP4_create + * Purpose: creates an instance of SGP4 + * Input: none + * Output: SGP4 + */ +SGP4 SGP4_create(void) { + return((SGP4)calloc(1, sizeof(struct sgp4_st))); + } + + +/* + * Name: SGP4_destroy + * Purpose: destroys an instance of SGP4 + * Input: SGP4 sgp4 + * Output: none + */ +void SGP4_destroy(SGP4 sgp4) { + if (sgp4) + free(sgp4); + } + + +/* + * Name: SGP4_init + * Purpose: initializes time-invariant SGP4 variables + * Input: SGP4 sgp4 + * Output: none + */ +void SGP4_init(SGP4 sgp4) { + double a1, del1, a0, del0, perigee, sStar, eta_2, eta_3, eta_4, pinvsq, + temp1, temp2, temp3, x3thetam1, x1m5th, xhdot1, theta_4, zeta, zeta_2, + zeta_3, zeta_5, beta0, beta0_3, beta0_4, C2; + + /* recover original mean motion and semimajor axis from the elements */ + a1=pow(KE/sgp4->n0, TWOBYTHREE); + del1=1.5 * (CK2/(a1*a1))*((3*cos(sgp4->i0)*cos(sgp4->i0)-1.0)/ + pow(1-sgp4->e0*sgp4->e0, 1.5)); + a0=a1*(1-del1/3.0-del1*del1-(134.0/81.0)*del1*del1*del1); + del0=(del1*a1*a1)/(a0*a0); + + /* find original mean motion, n0dp (n0'') */ + sgp4->n0dp=sgp4->n0/(1+del0); + + /* find semimajor axis, a0dp (a0'') */ + sgp4->a0dp=a0/(1-del0); + + /* find the perigee (in km) */ + perigee=(sgp4->a0dp*(1.0-sgp4->e0)-AE)*KM_PER_EARTH; + + /* make decisions on what value of s to use based on perigee */ + if (perigee<=156.0 && perigee>=98.0) { + sStar=sgp4->a0dp*(1.0-sgp4->e0)-S-AE; + sgp4->q0ms4=pow(pow(Q0MS4, 0.25) + S - sStar, 4); + } + else if (perigee<98.0) { + sStar=20/KM_PER_EARTH + AE; + sgp4->q0ms4=pow(pow(Q0MS4, 0.25) + S - sStar, 4); + } + else { + sStar=S; + sgp4->q0ms4=Q0MS4; + } + + sgp4->theta=cos(sgp4->i0); sgp4->theta_2=sgp4->theta*sgp4->theta; + theta_4=sgp4->theta_2*sgp4->theta_2; + zeta=1/(sgp4->a0dp-sStar); + + zeta_2=zeta*zeta, zeta_3=zeta_2*zeta; + sgp4->zeta_4=zeta_3*zeta; + zeta_5=sgp4->zeta_4*zeta; + + sgp4->beta0_2=1-sgp4->e0*sgp4->e0; + beta0=sqrt(sgp4->beta0_2); beta0_3=sgp4->beta0_2*beta0; + beta0_4=beta0_3*beta0; + + sgp4->eta=sgp4->a0dp*sgp4->e0*zeta; + eta_2=sgp4->eta*sgp4->eta, eta_3=eta_2*sgp4->eta, eta_4=eta_3*sgp4->eta; + + C2=sgp4->q0ms4*(sgp4->zeta_4)*sgp4->n0dp*pow(1-eta_2, -7.0/2.0)* + (sgp4->a0dp*(1+ ((3.0/2.0)*eta_2) + 4*sgp4->e0*sgp4->eta + + sgp4->e0*eta_3) + (3.0/2.0)*(CK2*zeta/(1-eta_2))*(-0.5 + + 1.5*sgp4->theta_2)*(8.0+24*eta_2 + 3*eta_4)); + sgp4->C1=sgp4->bstar*C2; sgp4->C1_2=sgp4->C1*sgp4->C1; + sgp4->C1_3=sgp4->C1_2*sgp4->C1; sgp4->C1_4=sgp4->C1_3*sgp4->C1; + sgp4->C3=(sgp4->q0ms4*(zeta_5)*A30*sgp4->n0dp*AE*sin(sgp4->i0))/ + (CK2*sgp4->e0); + sgp4->C4=2*sgp4->n0dp*sgp4->q0ms4*(sgp4->zeta_4)*sgp4->a0dp*(sgp4->beta0_2)* + pow(1-eta_2, -7.0/2.0)*( (2*sgp4->eta*(1+sgp4->e0*sgp4->eta)+ + 0.5*sgp4->e0+0.5*eta_3)-2*CK2*zeta/(sgp4->a0dp*(1-eta_2))* + (3*(1-3*sgp4->theta_2)*(1 + 1.5*eta_2 -2*sgp4->e0*sgp4->eta - + 0.5*sgp4->e0*eta_3) + 0.75*(1-sgp4->theta_2)*(2*eta_2 - + sgp4->e0*sgp4->eta - sgp4->e0*eta_3)*cos(2*sgp4->w0))); + sgp4->C5=2*sgp4->q0ms4*(sgp4->zeta_4)*sgp4->a0dp*(sgp4->beta0_2)* + pow(1-eta_2, -7.0/2.0)*(1 + (11.0/4.0)*sgp4->eta*(sgp4->eta+sgp4->e0)+ + sgp4->e0*eta_3); + + sgp4->D2=4*sgp4->a0dp*zeta*sgp4->C1_2; + sgp4->D3=(4.0/3.0)*sgp4->a0dp*zeta_2*(17*sgp4->a0dp + + sStar)*sgp4->C1_3; + sgp4->D4=TWOBYTHREE*sgp4->a0dp*zeta_3*(221*sgp4->a0dp+ + 31*sStar)*sgp4->C1_4; + + /* constants for secular effects calculation */ + pinvsq=1.0/(sgp4->a0dp*sgp4->a0dp*beta0_4); + temp1=3.0*CK2*pinvsq*sgp4->n0dp; + temp2=temp1*CK2*pinvsq; + temp3=1.25*CK4*pinvsq*pinvsq*sgp4->n0dp; + x3thetam1=3.0*sgp4->theta_2 - 1.0; + x1m5th=1.0 - 5.0*sgp4->theta_2; + xhdot1=-temp1*sgp4->theta; + + sgp4->mdot=sgp4->n0dp+0.5*temp1*beta0*x3thetam1+ + 0.0625*temp2*beta0*(13.0 - 78.0*sgp4->theta_2+137.0*theta_4); + + sgp4->wdot=-0.5*temp1*x1m5th+0.0625*temp2*(7.0-114.0*sgp4->theta_2+ + 395.0*theta_4)+temp3*(3.0-36.0*sgp4->theta_2+49.0*theta_4); + + sgp4->raandot=xhdot1+(0.5*temp2*(4.0-19.0*sgp4->theta_2)+2.0*temp3* + (3.0-7.0*sgp4->theta_2))*sgp4->theta; + } + + +/* + * Name: SGP4_getStateVector + * Purpose: finds position, velocity at a time + * Input: SGP4 sgp4, double t + * Output: double pos[3], double vel[3] + */ +void SGP4_getStateVector(SGP4 sgp4, double t, double pos[3], double vel[3]) { + double mdf, wdf, raandf, del_w, del_m, mp, w, RAAN, e, a, IL, + beta_2, n, axn, ILl, aynl, ILt, ayn, U, initial, eCosE, + eSinE, eL_2, pL, r, rDot, rfDot, cosu, sinu, u, rk, uk, RAANk, ik, + rDotk, rfDotk, mx, my, ux, uy, uz, vx, vy, vz, tsince; + int i; + + /* find the time since the epoch, in minutes */ + tsince=(t-sgp4->epochTime)*1440; + + /* secular effects of atmospheric drag and gravitation */ + mdf=sgp4->M0+(sgp4->mdot*tsince); + wdf=sgp4->w0+(sgp4->wdot*tsince); + raandf=sgp4->raan+(sgp4->raandot*tsince); + + del_w=sgp4->bstar*sgp4->C3*(cos(sgp4->w0))*tsince; + del_m=-TWOBYTHREE*sgp4->q0ms4*sgp4->bstar*sgp4->zeta_4* + (AE/(sgp4->e0*sgp4->eta))*(pow(1+sgp4->eta*cos(mdf), 3)- + pow(1+sgp4->eta*cos(sgp4->M0), 3)); + + mp=mdf+del_w+del_m; + w=wdf-del_w-del_m; + + RAAN=raandf-(21.0/2.0)*((sgp4->n0dp*CK2*sgp4->theta)/(sgp4->a0dp* + sgp4->a0dp*sgp4->beta0_2))* sgp4->C1*tsince*tsince; + e=sgp4->e0-sgp4->bstar*sgp4->C4*tsince-sgp4->bstar*sgp4->C5* + (sin(mp)-sin(sgp4->M0)); + + a=sgp4->a0dp*pow((1+tsince*(-sgp4->C1+tsince*(-sgp4->D2+tsince* + (-sgp4->D3-sgp4->D4*tsince)))), 2); + + IL=mp+w+RAAN+sgp4->n0dp*tsince*tsince*(1.5*sgp4->C1+tsince* + ((sgp4->D2+2*sgp4->C1_2) + tsince*(0.25*(3*sgp4->D3 + + 12*sgp4->C1*sgp4->D2 + 10*sgp4->C1_3)+tsince*(0.2*(3*sgp4->D4+12* + sgp4->C1*sgp4->D3+6*sgp4->D2*sgp4->D2+30*sgp4->C1_2*sgp4->D2+ + 15*sgp4->C1_4))))); + + beta_2=1-e*e; + n=KE/pow(a, 3.0/2.0); + + /* find the long-period periodic terms */ + axn=e*cos(w); + ILl=(A30*sin(sgp4->i0))/(8*CK2*a*beta_2)*(e*cos(w))*((3+5*sgp4->theta)/ + (1+sgp4->theta)); + aynl=(A30*sin(sgp4->i0))/(4*CK2*a*beta_2); + ILt=IL+ILl; + ayn=e*sin(w)+aynl; + + /* iteratively solve Kepler's equation */ + U=fmod(ILt-RAAN, TWOPI); + + initial=U; + for (i=0; i<10; i++) { + U=(initial-ayn*cos(U)+axn*sin(U)-U)/(1.0-ayn*sin(U)-axn*cos(U))+U; + } + + /* preliminary quantities for short period periodics */ + eCosE=axn*cos(U)+ayn*sin(U); + eSinE=axn*sin(U)-ayn*cos(U); + eL_2=axn*axn+ayn*ayn; + pL=a*(1-eL_2); + r=a*(1-eCosE); + rDot=KE*(sqrt(a)/r)*eSinE; + rfDot=KE*sqrt(pL)/r; + cosu=(a/r)*(cos(U)-axn+(ayn*eSinE)/(1+sqrt(1-eL_2))); + sinu=(a/r)*(sin(U)-ayn-(axn*eSinE)/(1+sqrt(1-eL_2))); + u=fmod(atan2(sinu, cosu)+TWOPI, TWOPI); + + /* update for short-period periodics */ + rk=r*(1-1.5*CK2*sqrt(1-eL_2)/(pL*pL)*(3*sgp4->theta_2-1))+ + (CK2/(2*pL))*(1-sgp4->theta_2)*cos(2*u); + uk=u+-(CK2/(4*pL*pL))*(7*sgp4->theta_2-1.0)*sin(2*u);; + RAANk=RAAN+((3*CK2*sgp4->theta)/(2*pL*pL))*sin(2*u); + ik=sgp4->i0+((3*CK2*sgp4->theta)/(2*pL*pL))*sin(sgp4->i0)*cos(2*u); + rDotk=rDot-((CK2*n)/pL)*(1-sgp4->theta_2)*sin(2*u); + rfDotk=rfDot+((CK2*n)/pL)*((1-sgp4->theta_2)*cos(2*u)- + 1.5*(1-3*sgp4->theta_2)); + + /* find the position and velocity components */ + mx=-sin(RAANk)*cos(ik); + my=cos(RAANk)*cos(ik); + + ux=mx*sin(uk)+cos(RAANk)*cos(uk); + uy=my*sin(uk)+sin(RAANk)*cos(uk); + uz=sin(ik)*sin(uk); + + vx=mx*cos(uk)-cos(RAANk)*sin(uk); + vy=my*cos(uk)-sin(RAANk)*sin(uk); + vz=sin(ik)*cos(uk); + + pos[0]=KM_PER_EARTH*rk*ux; + pos[1]=KM_PER_EARTH*rk*uy; + pos[2]=KM_PER_EARTH*rk*uz; + + vel[0]=MIN_PER_DAY*KM_PER_EARTH*(rDotk*ux+rfDotk*vx)/(AE*86400.0); + vel[1]=MIN_PER_DAY*KM_PER_EARTH*(rDotk*uy+rfDotk*vy)/(AE*86400.0); + vel[2]=MIN_PER_DAY*KM_PER_EARTH*(rDotk*uz+rfDotk*vz)/(AE*86400.0); + } + + +/* + * Name: SGP4_set + * Purpose: sets the elements of an instance of SGP4 + * Input: SGP4 sgp4, double epochTime, double n0dt, double n0dt2, + * double bstar, double i0, double raan, double e0, + * double w0, double M0, double n0 + * Output: none + */ +void SGP4_set(SGP4 sgp4, double epochTime, double n0dt, double n0dt2, + double bstar, double i0, double raan, double e0, + double w0, double M0, double n0) { + + /* set the epoch time */ + sgp4->epochTime=epochTime; + + /* set the first time derivative of mean motion */ + sgp4->n0dt=n0dt*(TWOPI/(MIN_PER_DAY*MIN_PER_DAY)); + + /* set the second time derivative of mean motion */ + sgp4->n0dt2=n0dt2*(TWOPI/(MIN_PER_DAY*MIN_PER_DAY)); + + /* bstar drag term */ + sgp4->bstar=bstar; + + /* inclination */ + sgp4->i0=DEG2RAD(i0); + + /* right ascension of the ascending node */ + sgp4->raan=DEG2RAD(raan); + + /* eccentricity */ + sgp4->e0=e0; + + /* argument of perigee */ + sgp4->w0=DEG2RAD(w0); + + /* mean anomaly */ + sgp4->M0=DEG2RAD(M0); + + /* mean motion */ + sgp4->n0=n0*(TWOPI/MIN_PER_DAY); + } + + +/* + * Name: SGP4_getPole + * Purpose: finds the pole (orbit plane normal) + * Input: double pos[3], double vel[3] + * Output: double pole[3] + */ +void SGP4_getPole(double pos[3], double vel[3], double pole[3]) { + register double pNorm; + + /* find the cross product between position and velocity */ + pole[0]=pos[1]*vel[2] - vel[1]*pos[2]; + pole[1]=pos[2]*vel[0] - vel[2]*pos[0]; + pole[2]=pos[0]*vel[1] - vel[0]*pos[1]; + + /* normalize the resulting pole vector */ + pNorm=sqrt(pole[0]*pole[0]+pole[1]*pole[1]+pole[2]*pole[2]); + pole[0]/=pNorm; pole[1]/=pNorm; pole[2]/=pNorm; + } + + +/* + * Name: SGP4_precess + * Purpose: precesses a direction vector from t1 to t2 + * Input: double v[3], double t1, double t2 + * Output: double v[3] + */ +void SGP4_precess(double v[3], double t1, double t2) { + double t, st, a, b, c, temp[3], sina, sinb, sinc, cosa, cosb, cosc; + + /* convert times to years */ + t=0.001*(t2-t1)/365.25; + st=0.001*(t1-MJD2000)/365.25; + + /* find the Euler angles */ + a=DEG2RAD(t*(23062.181+st*(139.656+0.0139*st)+ + +t*(30.188-0.344*st+17.998*t)))/3600.0; + b=DEG2RAD(t*t*(79.280+0.410*st+0.205*t)/3600.0)+a; + c=DEG2RAD(t*(20043.109-st*(85.33+0.217*st)+ + +t*(-42.665-0.217*st-41.833*t)))/3600.0; + + /* do the precession rotation */ + sina=sin(a); sinb=sin(b); sinc=sin(c); + cosa=cos(a); cosb=cos(b); cosc=cos(c); + temp[0]=(cosa*cosb*cosc-sina*sinb)*v[0]+(-cosa*sinb-sina*cosb*cosc)*v[1]+ + -cosb*sinc*v[2]; + temp[1]=(sina*cosb+cosa*sinb*cosc)*v[0]+(cosa*cosb-sina*sinb*cosc)*v[1]+ + -sinb*sinc*v[2]; + temp[2]=cosa*sinc*v[0]-sina*sinc*v[1]+cosc*v[2]; + + /* replace existing direction vector */ + v[0]=temp[0]; v[1]=temp[1]; v[2]=temp[2]; + } diff --git a/src/libcf/solar_ang.c b/src/libcf/solar_ang.c new file mode 100644 index 0000000..421d460 --- /dev/null +++ b/src/libcf/solar_ang.c @@ -0,0 +1,90 @@ +/****************************************************************************** + * Johns Hopkins University + * Center For Astrophysical Sciences + * FUSE + ****************************************************************************** + * + * Synopsis: double solar_ang(double mjdate, double ra, double dec) + * + * Description: Computes the angle between the Sun and J2000.0 RA and DEC + * for a given date. + * + * Arguments: double mjdate Modified Julian date of observation + * double ra (deg) J2000.0 right ascension + * double dec (deg) J2000.0 declination + * + * Returns: double (deg) angle between Sun and RA,DEC + * + * Calls: slaDcc2s dcc2s.f + * slaDsep dsep.f + * slaDranrm dranrm.f + * slaEvp evp.f + * + * History: 03/10/98 E. Murphy Begin work. + * 03/10/98 E. Murphy Initial version working + * 05/31/00 peb Implemented cfortran.h calls for slalib + * functions. + * 12/18/03 bjg Change calfusettag.h to calfuse.h + * 07/21/04 1.4 wvd Comment out variable vect; unused. + * + * References: This routine makes use of the Starlink set of astronomical + * subroutines (SLALIB). More information can be found at + * http://star-www.rl.ac.uk. + *****************************************************************************/ + +#include +#include + +#ifdef CFORTRAN +#include "cfortran.h" +PROTOCCALLSFSUB3(SLA_DCC2S, sla_dcc2s, DOUBLEV, PDOUBLE, PDOUBLE) +#define slaDcc2s(V, A, B) \ + CCALLSFSUB3(SLA_DCC2S, sla_dcc2s, DOUBLEV, PDOUBLE, PDOUBLE, V, A, B) +PROTOCCALLSFFUN1(DOUBLE, SLA_DRANRM, sla_dranrm, DOUBLE) +#define slaDranrm(ANGLE) \ + CCALLSFFUN1(SLA_DRANRM, sla_dranrm, DOUBLE, ANGLE) +PROTOCCALLSFFUN4(DOUBLE, SLA_DSEP, sla_dsep, DOUBLE, DOUBLE, DOUBLE, DOUBLE) +#define slaDsep(A1, B1, A2, B2) \ + CCALLSFFUN4(SLA_DSEP, sla_dsep, DOUBLE, DOUBLE, DOUBLE, DOUBLE, \ + A1, B1, A2, B2) +PROTOCCALLSFSUB6(SLA_EVP, sla_evp, DOUBLE, DOUBLE, DOUBLEV, DOUBLEV, DOUBLEV, \ + DOUBLEV) +#define slaEvp(DATE, DEQX, DVB, DPB, DVH, DPH) \ + CCALLSFSUB6(SLA_EVP, sla_evp, DOUBLE, DOUBLE, DOUBLEV, DOUBLEV, DOUBLEV, \ + DOUBLEV, DATE, DEQX, DVB, DPB, DVH, DPH) +#else +#include "slalib.h" +#include "slamac.h" +#endif + +#include "calfuse.h" + +double solar_ang(double mjdate, double ra, double dec) +{ + /* Define variables. */ + int i; + /* double dvb[3], dpb[3], dvh[3], dph[3], vect[3], ra_sun, dec_sun; */ + double dvb[3], dpb[3], dvh[3], dph[3], ra_sun, dec_sun; + /* + * Evp returns four 3-vectors containing the barycentric velocity and + * position (dvb,dpv) and the heliocentric velocity and position + * (dvh,dph) of the Earth on the date mjdate. It requires a modified + * Julian date as input. Output has units of AU for positions and + * AU/s for velocities. + */ + slaEvp(mjdate, 2000.0, dvb, dpb, dvh, dph); + + /* Convert the 3-vector position of the Sun into a J2000.0 RA and DEC */ + + for (i=0; i<3; i++) dph[i]*=-1.0; + +#ifdef CFORTRAN + slaDcc2s(dph, ra_sun, dec_sun); +#else + slaDcc2s(dph, &ra_sun, &dec_sun); +#endif + + /* Compute the angular separation of RA,DEC and RA_SUN and DEC_SUN */ + + return slaDsep(ra*RADIAN, dec*RADIAN, slaDranrm(ra_sun), dec_sun)/RADIAN; +} diff --git a/src/libcf/space_vel.c b/src/libcf/space_vel.c new file mode 100644 index 0000000..e472961 --- /dev/null +++ b/src/libcf/space_vel.c @@ -0,0 +1,46 @@ +/***************************************************************************** + * Johns Hopkins University + * Center For Astrophysical Sciences + * FUSE + ***************************************************************************** + * + * Synopsis: double space_vel(double *vel, double ra, double dec) + * + * Description: Computes the projection of the spacecraft orbital velocity + * vector onto a unit vector in the direction ra, dec. + * + * Arguments: double *vel (km/s) 3-vector velocity of satellite + * double ra,dec (deg) position of target + * + * Returns: double (km/s) velocity in direction of target + * + * History: 03/04/98 E. Murphy Begin work. + * 03/04/98 E. Murphy Initial version working + * 07/07/99 E. Murphy Converted x,y,z and vx,vy,vz to pos,vel + * 06/15/01 V. Dixon Comment out calculation of r, not used. + * 12/18/03 bjg Change calfusettag.h to calfuse.h + * 07/21/04 1.4 wvd Delete defn of r, as it is not used. + * 03/04/07 1.5 wvd Rewrite program to compute dot product + * of target and velocity vectors. + * + ****************************************************************************/ + +#include +#include "calfuse.h" + +double space_vel(double vel[3], double ra, double dec) +{ + + double x, y, z, phi; + + ra *= RADIAN; + dec *= RADIAN; + + z = sin(dec); + phi = cos(dec); + y = phi * sin(ra); + x = phi * cos(ra); + + return x*vel[0] + y*vel[1] + z*vel[2]; + +} diff --git a/src/libcf/state_geod.c b/src/libcf/state_geod.c new file mode 100644 index 0000000..4e0c161 --- /dev/null +++ b/src/libcf/state_geod.c @@ -0,0 +1,107 @@ +/****************************************************************************** + * Johns Hopkins University + * Center For Astrophysical Sciences + * FUSE + ****************************************************************************** + * + * Synopsis: void state_geod(double pos, + * double mjdate, double lon, double lat) + * + * Description: Computes the geocentric longitude and latitude of FUSE + * from the given state 6-vector. + * + * Arguments: double pos (km) 3-vector xyz position of satellite + * double mjdate Modified Julian date of observation + * + * Returns: double lon, lat (deg) Geocentric longitude and latitude + * + * Calls: slaPreces preces.f + * + * History: 03/04/98 E. Murphy Begin work. + * 03/04/98 E. Murphy Initial version working + * 03/15/99 E. murphy Changed function definition to void + * (was double) + * 07/07/99 E. Murphy Changed call to use pos instead of x,y,z + * 05/31/00 peb Implemented cfortran.h calls for slalib + * functions. + * 12/18/03 bjg Change calfusettag.h to calfuse.h + * 06/17/04 bjg 1.4 Corrected cfortran call to sla_preces + * + * Ake, T. 1998 in The Scientific Impact of the Goddard + * High Resolution Spectrograph, ed. J. C. Brandt et al., + * ASP Conference Series, in preparation. + *****************************************************************************/ + +#include +#include + +#ifdef CFORTRAN +#include "cfortran.h" +PROTOCCALLSFSUB5(SLA_PRECES, sla_preces, STRING, DOUBLE, DOUBLE, PDOUBLE, \ + PDOUBLE) +#define slaPreces(SYSTEM, EP0, EP1, RA, DC) \ + CCALLSFSUB5(SLA_PRECES, sla_preces, STRING, DOUBLE, DOUBLE, PDOUBLE, \ + PDOUBLE, SYSTEM, EP0, EP1, RA, DC) +#else +#include "slalib.h" +#include "slamac.h" +#endif + +#include "calfuse.h" + +void state_geod(double pos[3], double mjdate, + double *lon, double *lat, double *gmst) +{ + double ra, dec, epoch2, c1, r, intmjd, frcmjd; + char fk5_st[10]="FK5"; + + /* pos[0]=x + pos[1]=y + pos[2]=z + */ + + r=sqrt(pos[0]*pos[0]+pos[1]*pos[1]+pos[2]*pos[2]); + ra=atan2(pos[1],pos[0]); + dec=asin(pos[2]/r); + + /* We must precess the J2000 RA and DEC to date of observation. This + * is a very small correction, and could probably be ignored. + */ + + epoch2=2000.0-((51544.0-mjdate)/365.25); + +#ifdef CFORTRAN + slaPreces(fk5_st, 2000.0, epoch2, ra, dec); +#else + slaPreces(fk5_st, 2000.0, epoch2, &ra, &dec); +#endif + + /* Calculate the Greenwich Mean Sidereal Time in seconds + * Astronomical Almanac, 1998, p. B6. + */ + + frcmjd=modf(mjdate, &intmjd); + + c1=(intmjd-51544.5)/36525.0; + + /* The following line gives the GMST at 0 hr UT */ + *gmst=24110.54841 + 8640184.812866*c1+0.093104*c1*c1-6.2E-6*c1*c1*c1; + /* The following adds on the number of seconds since the UT above */ + *gmst+=frcmjd*1.00273791*86400.0; + + *gmst*=(2*M_PI)/86400.0; + + while (*gmst < 0.0) *gmst+=2*M_PI; + + while (*gmst > 2*M_PI) *gmst-=2*M_PI; + + *lon=(ra-*gmst)/RADIAN; + + while (*lon > 180.0) *lon-=360.0; + + while (*lon < -180.0) *lon+=360.0; + + *lat=dec/RADIAN; + + *gmst*=24.0/(2*M_PI); +} diff --git a/src/libcf/state_limb.c b/src/libcf/state_limb.c new file mode 100644 index 0000000..9aacfb6 --- /dev/null +++ b/src/libcf/state_limb.c @@ -0,0 +1,159 @@ +/***************************************************************************** + * Johns Hopkins University + * Center For Astrophysical Sciences + * FUSE + ***************************************************************************** + * + * Synopsis: double state_limb(double pos[3], double mjdate, + * double ra, double dec, double *zdis,tint day_limb) + * + * Description: Computes the earth limb angle from J2000 RA and DEC given + * the 3-vector position of FUSE. + * + * Arguments: double pos (km) 3-vector position of satellite + * double mjdate (days) Modified Julian date + * double ra,dec (deg) J2000.0 RA and DEC + * double zdist (deg) zenith angle + * integer day_limb output : 1 if bright limb, 0 if dark limb + * + * Returns: double (deg) Earth limb angle + * integer day_limb will have the value 1 or 0 when + * returning in the main program. + * + * Calls: slaPreces preces.f + * slaDcc2s + * slaDranrm + * slaEvp + * + * History: 03/10/98 E. Murphy Begin work. + * 03/10/98 E. Murphy Initial version working + * 07/07/99 E. Murphy Changed call to use pos instead of x,y,z + * 08/26/99 E. Murphy Added zenith distance. + * 05/31/00 peb Implemented cfortran.h calls for slalib + * functions. + * Ake, T. 1998 in The Scientific Impact of the Goddard + * High Resolution Spectrograph, ed. J. C. Brandt et al., + * ASP Conference Series, in preparation. + * + * 09/23/00 v1.5 ma Now this function determine bright or + * dark limb + * To do so, the procedure has a new + * input argument: day_limb. + * day_limb = 1 if bright, 0 if dark. + * 09/24/00 v1.6 ma Fixed a bug in the input argument + * 09/27/00 v1.7 ma Fixed bug in limbvec calc. + * 10/02/00 v1.8 jwk Add fortran wrappers for slaDcc2s, + * slaEvp, and slaDranrm + * 12/18/03 bjg 1.3 Change calfusettag.h to calfuse.h + * 06/17/04 bjg Corrected cfortran call to sla_preces + * 07/22/04 bjg 1.4 Remove unused variables + ****************************************************************************/ + +#include + +#ifdef CFORTRAN +#include "cfortran.h" +PROTOCCALLSFSUB5(SLA_PRECES, sla_preces, STRING, DOUBLE, DOUBLE, PDOUBLE, \ + PDOUBLE) +#define slaPreces(SYSTEM, EP0, EP1, RA, DC) \ + CCALLSFSUB5(SLA_PRECES, sla_preces, STRING, DOUBLE, DOUBLE, PDOUBLE, \ + PDOUBLE, SYSTEM, EP0, EP1, RA, DC) +PROTOCCALLSFSUB3(SLA_DCC2S, sla_dcc2s, DOUBLEV, PDOUBLE, PDOUBLE) +#define slaDcc2s(V, A, B) \ + CCALLSFSUB3(SLA_DCC2S, sla_dcc2s, DOUBLEV, PDOUBLE, PDOUBLE, V, A, B) +PROTOCCALLSFFUN1(DOUBLE, SLA_DRANRM, sla_dranrm, DOUBLE) +#define slaDranrm(ANGLE) \ + CCALLSFFUN1(SLA_DRANRM, sla_dranrm, DOUBLE, ANGLE) +PROTOCCALLSFSUB6(SLA_EVP, sla_evp, DOUBLE, DOUBLE, DOUBLEV, DOUBLEV, DOUBLEV, \ + DOUBLEV) +#define slaEvp(DATE, DEQX, DVB, DPB, DVH, DPH) \ + CCALLSFSUB6(SLA_EVP, sla_evp, DOUBLE, DOUBLE, DOUBLEV, DOUBLEV, DOUBLEV, \ + DOUBLEV, DATE, DEQX, DVB, DPB, DVH, DPH) +#else +#include "slalib.h" +#include "slamac.h" +#endif + +#include "calfuse.h" + +double state_limb(double pos[3], double mjdate, + double ra, double dec, double *zdist,int *day_limb) +{ + double dvb[3], dpb[3], dvh[3], dph[3], limbvec[3], epoch2; + double ra_earth, dec_earth, r, ndist; + double ra_sun, dec_sun; + int i; + char fk5_st[10]="FK5"; + + ra*=RADIAN; + dec*=RADIAN; + + r=sqrt(pos[0]*pos[0]+pos[1]*pos[1]+pos[2]*pos[2]); + ra_earth=atan2(-pos[1],-pos[0]); + dec_earth=asin(-pos[2]/r); + /* + * We must precess the J2000 RA and DEC to date of observation. This + * is a very small correction, and could probably be ignored. + */ + epoch2=2000.0-((51544.0-mjdate)/365.25); + +#ifdef CFORTRAN + slaPreces(fk5_st, 2000.0, epoch2, ra_earth, dec_earth); +#else + slaPreces(fk5_st, 2000.0, epoch2, &ra_earth, &dec_earth); +#endif + + /* Now we need the position of the sun (same code as in eclipse.c) */ + + slaEvp(mjdate, 2000.0, dvb, dpb, dvh, dph); + + /* Convert the 3-vector position of the Sun into a J2000.0 RA and DEC */ + + for (i=0; i<3; i++) dph[i]*=-1.0; + + +#ifdef CFORTRAN + slaDcc2s(dph, ra_sun, dec_sun); +#else + slaDcc2s(dph, &ra_sun, &dec_sun); +#endif + + ra_sun=slaDranrm(ra_sun); + + /* We must precess the J2000 RA and DEC to date of observation. This + * is a very small correction, and could probably be ignored. + */ + + epoch2=2000.0-((51544.0-mjdate)/365.25); + +#ifdef CFORTRAN + slaPreces(fk5_st, 2000.0, epoch2, ra_sun, dec_sun); +#else + slaPreces(fk5_st, 2000.0, epoch2, &ra_sun, &dec_sun); +#endif + + /* ndist is the angular distance (RADIAN) from the nadir to the target */ + ndist = (acos(sin(dec)*sin(dec_earth)+ + cos(dec)*cos(dec_earth)*cos(ra-ra_earth))); + + /* Now we want to calculate the limb vector (originating at the center + of Earth and crossing the target-FUSE line perpendicularily)*/ + + limbvec[2]=pos[2]+r*cos(ndist)*sin(dec); + limbvec[1]=pos[1]+r*cos(ndist)*cos(dec)*sin(ra); + limbvec[0]=pos[0]+r*cos(ndist)*cos(dec)*cos(ra); + + /* Now we do the scalar product with the sun vector; then + if the result is <0 the limb is in the day zone (less + than 90 degrees between sun vector and limb vector)*/ + + if ((limbvec[0]*cos(dec_sun)*cos(ra_sun) + + limbvec[1]*cos(dec_sun)*sin(ra_sun)+limbvec[2]*sin(dec_sun)) >0) { + *day_limb=1; + } else { + *day_limb=0; + } + *zdist = 180.0 - ndist/RADIAN; + + return ndist/RADIAN-(asin(RE/r)/RADIAN); +} -- cgit