aboutsummaryrefslogtreecommitdiff
path: root/src/libcf/cf_satellite_jitter.c
blob: 9f3a5d9104bc264b98e6f72d071ca277995d5911 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
/*****************************************************************************
 *              Johns Hopkins University
 *              Center for Astrophysical Sciences
 *              FUSE
 *****************************************************************************
 *
 * Synopsis:    cf_satellite_jitter infile, nevents, time, x, y, channel,
 *              	nsec, ttime, status_flag)
 *
 * Description: Correct photon coordinates for spacecraft motion.
 *
 *		Operates only on point-source observations made in TTAG mode.
 *		Only photon events in the target aperture are corrected.
 *		Minimum trustworthy TRKFLG value is read from 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, but q_cmd from FITS header coords
 *      	1 = dx, dy from ACS q_est, but q_cmd from FITS header coordis
 *      	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      nevents       The number of events
 *              float     *time         An array of event times
 *              float     *x            An array of event X positions
 *              float     *y            An array of event Y positions
 *     unsigned char      *channel      Channel assignment for each photon
 *              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:     09/12/02   v1.1   RDR   Adapted from cf_ttag_jitter
 *              10/02/02   v1.2   RDR   Modified to be compatable with
 *                                      new IDF file format
 *              12/10/02   v1.3   RDR   Adjusted method of populating the 
 *                                      timeline jitter status flag. 
 *              12/13/02   v1.4   RDR   Exit gracefully if there is no jitr file 
 *              03/01/03   v1.6   wvd   Correct use of pointer in FITS_read_key
 *              04/07/03   v1.7   wvd   Confirm that TRKFLG <= 5.
 *					Replace printf with cf_verbose.
 *              04/14/03   v1.8   rdr   Changed flag from char to unsigned char
 *              04/22/03   v1.9   wvd   Move only photons in target aperture.
 *					Do not assume that ttime is continuous.
 *              04/29/03   v1.10  wvd   Allow possiblity that jitter
 *                                      filename is in lower-case letters.
 *              05/20/03   v1.11  rdr   Added call to cf_proc_check
 *              05/22/03   v1.12  wvd   Direct cf_error_init to stderr
 *              07/11/03   v1.13  rdr   Set all points as bad if JIT_STAT=1
 *                                       (no reference position found)
 *              08/06/03   v1.14  wvd   Improve documentation, delete
 *					comparison with GTI's, change channel
 *					array to unsigned char.
 *              08/29/03   v1.15  wvd   Set all points as bad if JIT_STAT != 0
 *              09/18/03   v1.16  wvd   Print name of jitter file only if
 *					the file exists.
 *              10/03/03   v1.17  wvd   Check HKEXISTS before looking for 
 *					jitter file.
 *              02/12/04   v1.18  wvd   Make interpolation immune
 *					to errors in jitter time array.
 *              02/24/04   v1.19  rdr   Change limits of acceptable jitter
 *					values
 *              03/01/04   v1.20  rdr   Populate the PLATESC keyword in the
 *					input file header
 *              06/01/04   v1.21  bjg   Exit when keyword JIT_STAT not found.
 *              06/07/04   v1.22  wvd   Return EXP_JITR to calling routine.
 *		01/26/05   v1.23  wvd   Fix tiny bug in a verbose stmt.
 *		04/05/05   v1.24  wvd   If JIT_STAT != 0, APERTURE = RFPT,
 *					or target = airglow, exit without 
 *					flagging any times as bad.
 *					Use new TRKFLG values (see above).
 *					Delete adjust_trkflg subroutine and
 *					the J_TRKFLG and JTIMEGAP keywords.
 *					Use cf_read_col to read jitter file.
 *		07/06/05   v1.25  wvd   If JIT_VERS < 2.0, issue a warning.
 *		11/29/05   v1.26  wvd	Move screening functions into 
 *					cf_screen_jitter.
 *              08/21/06   v1.27  wvd   Use EXPSTART in jitter and data
 *                                      headers to correct jitter time array.
 *              08/25/06   v1.28  wvd   Change meaning of TRKFLG values.
 *                                      TRKFLG = 3 is only used internally.
 *              11/06/06   v1.29  wvd   Change meaning of TRKFLG values.
 *					Read APER_COR keyword in file header.
 *					Read min TRKFLG value from parmfile.
 *					Don't have to test observing mode.
 *              03/23/07   v1.30  wvd   Store offset between the jitter and 
 *					data values of EXPSTART in variable
 *					time_diff.
 *              04/07/07   v1.31  wvd   Clean up compiler warnings.
 *
 ****************************************************************************/

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#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<nevents; j++) {
	while (ttime[k+1] - FRAME_TOLERANCE < time[j] && k+1 < nsec) k++;
	    if (channel[j] == active_ap[0] || channel[j] == active_ap[1]) {
		if (status_flag[k] & TEMPORAL_JITR) nrej++;
		else {
		   x[j] += dx_tt[k];
		   y[j] += dy_tt[k];
		}
	    }
    }

    /* Write to trailer file */
    cf_verbose(2, "Rejected %ld photons from target aperture", nrej);

    /* Deallocate storage space */
    free(time_jit);
    free(dx_jit);
    free(dy_jit);
    free(trkflg);
    free(dx_tt);
    free(dy_tt);
   
    cf_proc_update(infits, CF_PRGM_ID, "COMPLETE");
    cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Finished processing");

    return (status);
}