aboutsummaryrefslogtreecommitdiff
path: root/src/libcf/cf_mirror_motion.c
blob: d5dd3b3a1d8e367fc5596f3f49b29f71363c0924 (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
/*****************************************************************************
 *	        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 <string.h>
#include <stdio.h>
#include <stdlib.h>
#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<ntimes; k++) {
	frac = tsunset[k] / period * 100.;
	ndx = (long) frac;
	if (ndx >= 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<nevents; j++) {
        while(ttime[k+1] - FRAME_TOLERANCE < time[j] && k+1 < ntimes) k++;
	/*
	 *  Shift only photons in the active aperture.
	 *  active_ap[0] = lif, active_ap[1] = sic 
	 */
	if (channel[j] == active_ap[0]) {
            x[j] += dxlif[k];
            y[j] += dylif[k];

        }
	if (channel[j] == active_ap[1]) {
            x[j] += dxsic[k];
            y[j] += dysic[k];
        }
    }

    /* Release array storage */
    free(tdxlif);
    free(tdxsic);
    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;
}