VIRCAM Pipeline  1.3.3
vircam_pawsky_minus.c
1 /* $Id: vircam_pawsky_minus.c,v 1.1 2013-10-15 16:30:07 jim Exp $
2  *
3  * This file is part of the VIRCAM Pipeline
4  * Copyright (C) 2013 Cambridge Astronomy Survey Unit
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  */
20 
21 /*
22  * $Author: jim $
23  * $Date: 2013-10-15 16:30:07 $
24  * $Revision: 1.1 $
25  * $Name: not supported by cvs2svn $
26  */
27 
28 /* Includes */
29 
30 #ifdef HAVE_CONFIG_H
31 #include <config.h>
32 #endif
33 
34 #include <cpl.h>
35 #include <math.h>
36 #include <string.h>
37 
38 #include "vircam_sky.h"
39 #include "vircam_mask.h"
40 #include "vircam_fits.h"
41 #include "vircam_mods.h"
42 #include "vircam_utils.h"
43 #include "vircam_stats.h"
44 #include "vircam_wcsutils.h"
45 
46 static void masksky_zeros(float **datas, unsigned char **masks, int nfiles,
47  int npts, float **zeros);
48 static void combine(int nfiles, int stat, int npts, float **datas,
49  unsigned char **masks, float **skyout,
50  unsigned char **skyout_bpm);
51 static void combine_mult(int nfiles, int stat, int npts, float **datas,
52  unsigned char **masks, float *skyout);
53 static void domed(float *buf, int n, float *val);
54 
55 extern int vircam_pawsky_minus(vir_fits **infiles, vir_fits *conf,
56  vir_fits *objmaskfits, int nfiles, int nconfs,
57  vir_fits **skyout, int *status) {
58  cpl_wcs *wcsmask,*wcsimg;
59  unsigned char **masks,*sky_bpm;
60  cpl_image *im,*skyim;
61  double *xin,*yin,*xout,*yout,*dx,*dy,ddx,ddy;
62  int nx,ny,npts,ind,i,j,*confdata,nx_mask,ny_mask,kind,ix,iy,jx,jy,*opm;
63  float **datas,*sky,*zeros,val,sig;
64  cpl_propertylist *plist;
65  const char *fctid = "vircam_pawsky_minus";
66 
67  /* Inherited status */
68 
69  *skyout = NULL;
70  if (*status != VIR_OK)
71  return(*status);
72 
73  /* If there aren't any images, then get out of here */
74 
75  if (nfiles == 0) {
76  cpl_msg_error(fctid,"Sky correction impossible. No science frames");
77  return(VIR_FATAL);
78  }
79 
80  /* Get space for arrays */
81 
82  datas = cpl_malloc(nfiles*sizeof(float *));
83  masks = cpl_malloc(nfiles*sizeof(unsigned char *));
84  im = vircam_fits_get_image(infiles[0]);
85  nx = cpl_image_get_size_x(im);
86  ny = cpl_image_get_size_y(im);
87  npts = nx*ny;
88 
89  /* Info about object mask if it exists */
90 
91  if (objmaskfits != NULL) {
92  nx_mask = cpl_image_get_size_x(vircam_fits_get_image(objmaskfits));
93  ny_mask = cpl_image_get_size_y(vircam_fits_get_image(objmaskfits));
94  wcsmask = cpl_wcs_new_from_propertylist(vircam_fits_get_ehu(objmaskfits));
95  opm = cpl_image_get_data_int(vircam_fits_get_image(objmaskfits));
96 
97  /* We need this space so that we can work out which part of the
98  input mask is relevant for each input image */
99 
100  xin = cpl_malloc(npts*sizeof(double));
101  yin = cpl_malloc(npts*sizeof(double));
102  xout = cpl_malloc(npts*sizeof(double));
103  yout = cpl_malloc(npts*sizeof(double));
104  dx = cpl_malloc(nfiles*sizeof(double));
105  dy = cpl_malloc(nfiles*sizeof(double));
106 
107  /* Initialise the input xy arrays */
108 
109  ind = 0;
110  for (j = 0; j < ny; j++) {
111  for (i = 0; i < nx; i++) {
112  xin[ind] = (double)(i+1);
113  yin[ind++] = (double)(j+1);
114  }
115  }
116 
117  /* Define an output grid for the first image and then offsets for
118  the subsequent images */
119 
120  ddx = 1.0;
121  ddy = 1.0;
122  for (i = 0; i < nfiles; i++) {
123  wcsimg = cpl_wcs_new_from_propertylist(vircam_fits_get_ehu(infiles[i]));
124  if (i == 0)
125  vircam_xytoxy_list(wcsimg,wcsmask,npts,xin,yin,xout,yout);
126  vircam_xytoxy_list(wcsimg,wcsmask,1,&ddx,&ddy,dx+i,dy+i);
127  dx[i] -= xout[0];
128  dy[i] -= yout[0];
129  cpl_wcs_delete(wcsimg);
130  }
131  cpl_wcs_delete(wcsmask);
132  }
133 
134  /* Loop for each file and get a reference for the data array. Get
135  some space for a mask that will cover both the zeroed pixels in the
136  confidence maps and any object mask that might be used */
137 
138  for (i = 0; i < nfiles; i++) {
139  im = vircam_fits_get_image(infiles[i]);
140  datas[i] = cpl_image_get_data_float(im);
141  masks[i] = cpl_calloc(npts,sizeof(unsigned char));
142  if (i == 0)
143  confdata = cpl_image_get_data_int(vircam_fits_get_image(conf));
144 
145  /* Now loop for each pixel. If the confidence map is zero here then
146  mark this as a bad pixel. If not, then look at the master mask
147  and see which is its closest pixel to the current one. NB: the
148  -0.5 in the index is a combination of +0.5 to do a nint and a -1
149  to take account of the fact that arrays start from index zero. */
150 
151  for (jy = 0; jy < ny; jy++) {
152  for (jx = 0; jx < nx; jx++) {
153  ind = jy*nx + jx;
154  if (confdata[ind] == 0) {
155  masks[i][ind] = 1;
156  } else if (objmaskfits != NULL) {
157  kind = (int)(yout[ind] + dy[i] - 0.5)*nx_mask +
158  (int)(xout[ind] + dx[i] - 0.5);
159  masks[i][ind] = opm[kind];
160  }
161  }
162  }
163  }
164 
165  /* Do an intermediate tidy */
166 
167  if (objmaskfits != NULL) {
168  freespace(xin);
169  freespace(yin);
170  freespace(xout);
171  freespace(yout);
172  freespace(dx);
173  freespace(dy);
174  }
175 
176  /* Offset the DC level */
177 
178  masksky_zeros(datas,masks,nfiles,npts,&zeros);
179 
180  /* Right, combine these now */
181 
182  combine(nfiles,0,npts,datas,masks,&sky,&sky_bpm);
183 
184  /* Wrap the sky and reject the pixels that had no sky contribution */
185 
186  skyim = cpl_image_wrap_float(nx,ny,sky);
187  for (i = 0; i < npts; i++) {
188  iy = i/nx + 1;
189  ix = npts - (iy-1)*nx;
190  if (sky_bpm[i])
191  cpl_image_reject(skyim,(cpl_size)ix,(cpl_size)iy);
192  }
193  freespace(sky_bpm);
194  *skyout = vircam_fits_wrap(skyim,infiles[0],NULL,NULL);
195  plist = vircam_fits_get_ehu(*skyout);
196  if (objmaskfits != NULL) {
197  cpl_propertylist_update_string(plist,"ESO DRS MASKUSED",
198  vircam_fits_get_filename(objmaskfits));
199  cpl_propertylist_set_comment(plist,"ESO DRS MASKUSED",
200  "Object masked used to make sky");
201  }
202  cpl_propertylist_update_string(plist,"ESO DRS SKYALGO","pawsky_minus");
203  cpl_propertylist_set_comment(plist,"ESO DRS SKYALGO",
204  "Sky estimation algorithm");
205  vircam_prov(plist,infiles,nfiles);
206 
207  /* Fill in the bits with no sky contribution */
208 
209  vircam_inpaint(*skyout,64,status);
210 
211  /* Do the multiple combine and subtraction */
212 
213  combine_mult(nfiles,0,npts,datas,masks,sky);
214 
215  /* Now add the DC level back onto the data */
216 
217  for (i = 0; i < nfiles; i++) {
218  vircam_qmedsig(datas[i],masks[i],(long)npts,3.0,1,-1000.0,65535.0,&val,
219  &sig);
220  val = zeros[i] - val;
221  for (j = 0; j < npts; j++)
222  datas[i][j] += val;
223  }
224  freespace(zeros);
225 
226  /* Add a little something to the header and start cleaning up */
227 
228  for (i = 0; i < nfiles; i++) {
229  plist = vircam_fits_get_ehu(infiles[i]);
230  cpl_propertylist_update_string(plist,"ESO DRS SKYSUB",
231  "Done with pawsky_minus");
232  freespace(masks[i]);
233  }
234  freespace(masks);
235  freespace(datas);
236  return(VIR_OK);
237 }
238 
239 static void masksky_zeros(float **datas, unsigned char **masks, int nfiles,
240  int npts, float **zeros) {
241  int i,j;
242  float sig,off,medval;
243 
244  /* Get some space for the zeros */
245 
246  *zeros = cpl_malloc(nfiles*sizeof(float));
247 
248  /* Loop for each input image and get the background median */
249 
250  for (i = 0; i < nfiles; i++)
251  vircam_qmedsig(datas[i],masks[i],(long)npts,3.0,1,-1000.0,
252  65535.0,*zeros+i,&sig);
253 
254  /* Get the median value of the array */
255 
256  medval = vircam_med(*zeros,NULL,nfiles);
257 
258  /* Now work out the offset for each image and subtract it */
259 
260  for (i = 0; i < nfiles; i++) {
261  off = medval - (*zeros)[i];
262  for (j = 0; j < npts; j++)
263  datas[i][j] += off;
264  }
265 }
266 
267 static void combine(int nfiles, int stat, int npts, float **datas,
268  unsigned char **masks, float **skyout,
269  unsigned char **skyout_bpm) {
270  int i,j,n;
271  float *buf;
272 
273  /* Get workspace for output arrays */
274 
275  *skyout = cpl_malloc(npts*sizeof(float));
276  *skyout_bpm = cpl_malloc(npts*sizeof(unsigned char));
277  buf = cpl_malloc(nfiles*sizeof(float));
278 
279  /* Loop now for each input pixel and form the median */
280 
281  for (j = 0; j < npts; j++) {
282  n = 0;
283  for (i = 0; i < nfiles; i++) {
284  if (masks[i][j] == 0)
285  buf[n++] = datas[i][j];
286  }
287  if (n == 0) {
288  (*skyout)[j] = 0.0;
289  (*skyout_bpm)[j] = 1;
290  } else {
291  if (stat == 0)
292  domed(buf,n,(*skyout)+j);
293  else
294  (*skyout)[j] = vircam_mean(buf,NULL,n);
295  (*skyout_bpm)[j] = 0;
296  }
297  }
298 
299  /* Free some workspace and get out of here */
300 
301  freespace(buf);
302  return;
303 }
304 
305 static void combine_mult(int nfiles, int stat, int npts, float **datas,
306  unsigned char **masks, float *skyout) {
307  int i,j,k,n;
308  float *buf,*val;
309 
310  /* Get some memory */
311 
312  buf = cpl_malloc(nfiles*sizeof(float));
313  val = cpl_malloc(nfiles*sizeof(float));
314 
315  /* Loop now for each input pixel */
316 
317  for (j = 0; j < npts; j++) {
318 
319  /* Loop for each file. If the current pixel in the current file
320  was flagged, then the sky for that pixel will be the same as
321  the general sky we did before. If not, then remove that file's
322  pixel and recalculate the sky */
323 
324  for (i = 0; i < nfiles; i++) {
325  if (masks[i][j] != 0) {
326  val[i] = skyout[j];
327  } else {
328  n = 0;
329  for (k = 0; k < nfiles; k++) {
330  if (k == i || masks[k][j] != 0)
331  continue;
332  buf[n++] = datas[k][j];
333  }
334  if (n == 0) {
335  val[i] = skyout[j];
336  } else {
337  if (stat == 0)
338  domed(buf,n,val+i);
339  else
340  val[i] = vircam_mean(buf,NULL,n);
341  }
342  }
343  }
344 
345  /* Now correct these pixels in the input images */
346 
347  for (i = 0; i < nfiles; i++)
348  datas[i][j] -= val[i];
349  }
350 
351  /* Free some workspace and get out of here */
352 
353  freespace(buf);
354  freespace(val);
355  return;
356 }
357 
358 
359 static void domed(float *buf, int n, float *val) {
360  int is_even,n2;
361 
362  is_even = ! (n & 1);
363  vircam_sort(&buf,n,1);
364  n2 = n/2;
365  if (is_even) {
366  *val = 0.5*(buf[n2-1] + buf[n2]);
367  } else {
368  if (n <= 5)
369  *val = buf[n2];
370  else
371  *val = 0.5*buf[n2] + 0.25*(buf[n2-1] + buf[n2+1]);
372  }
373 }
374 
375 /*
376 
377 $Log: not supported by cvs2svn $
378 
379 */
380