VIRCAM Pipeline  2.3.12
casu_sky.c
1 /* $Id: casu_sky.c,v 1.2 2015/08/07 13:06:54 jim Exp $
2  *
3  * This file is part of the CASU Pipeline utilities
4  * Copyright (C) 2015 European Southern Observatory
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: 2015/08/07 13:06:54 $
24  * $Revision: 1.2 $
25  * $Name: $
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 "casu_sky.h"
39 #include "casu_mask.h"
40 #include "catalogue/casu_fits.h"
41 #include "casu_mods.h"
42 #include "catalogue/casu_utils.h"
43 #include "casu_stats.h"
44 #include "catalogue/casu_wcsutils.h"
45 
46 static void casu_sky_mask_grow(cpl_image *dith, float rad);
47 static float casu_sky_med(casu_fits *sky);
48 static void casu_sky_joffs(casu_fits **inlist, int nfiles, float **xoffs,
49  float **yoffs);
50 static void casu_sky_xytoxy(cpl_wcs *inwcs, cpl_wcs *outwcs,
51  cpl_matrix *inxy, cpl_matrix **outxy);
52 
55 /*---------------------------------------------------------------------------*/
108 /*---------------------------------------------------------------------------*/
109 
110 extern int casu_pawsky_mask(casu_fits **inlist, casu_fits **invar, int nfiles,
111  casu_fits *conf, casu_mask *mask,
112  casu_fits **skyout, casu_fits **skyvar, int niter,
113  int ipix, float thresh, int nbsize, float smkern,
114  int *status) {
115  int i,nx,ny,nbad0,lastone,iter,npts,nbad_init,nbad,dbad;
116  int xx1,xx2,yy1,yy2,nfiles2,*confdata;
117  const char *fctid = "casu_pawsky_mask";
118  cpl_image *dith,*dithc,*skyim,*im,*newim,*outim,*outimv;
119  cpl_mask *cplmask,*dithmask,*newmask,*curmask;
120  casu_fits **list_ss,*dithf,*dithcf,**inlist2,**invar2;
121  unsigned char *inbpm,*rejmask,*rejplus;
122  float medsky,*xoffs,*yoffs,mindx,mindy,fbad;
123  cpl_propertylist *p,*drs;
124 
125  /* Inherited status */
126 
127  *skyout = NULL;
128  *skyvar = NULL;
129  if (*status != CASU_OK)
130  return(*status);
131 
132  /* If there aren't any images, then get out of here */
133 
134  if (nfiles == 0) {
135  cpl_msg_error(fctid,"Sky correction impossible. No science frames");
136  FATAL_ERROR
137  }
138 
139  /* Check to see which files are good */
140 
141  inlist2 = cpl_malloc(nfiles*sizeof(casu_fits *));
142  if (invar != NULL)
143  invar2 = cpl_malloc(nfiles*sizeof(casu_fits *));
144  else
145  invar2 = NULL;
146  nfiles2 = 0;
147  for (i = 0; i < nfiles; i++) {
148  if (casu_fits_get_status(inlist[i]) == CASU_OK) {
149  inlist2[nfiles2] = inlist[i];
150  if (invar != NULL)
151  invar2[nfiles2] = invar[i];
152  nfiles2++;
153  }
154  }
155 
156  /* If no good images are present then wrap a dummy image and return it */
157 
158  if (nfiles2 == 0) {
159  outim = casu_dummy_image(inlist[0]);
160  *skyout = casu_fits_wrap(outim,inlist[0],NULL,NULL);
162  casu_fits_set_status(*skyout,CASU_FATAL);
163  if (invar != NULL) {
164  outimv = casu_dummy_image(inlist[0]);
165  *skyvar = casu_fits_wrap(outimv,inlist[0],NULL,NULL);
167  } else {
168  *skyvar = NULL;
169  }
170  cpl_msg_warning(fctid,"No good images in input list");
171  freespace(inlist2);
172  freespace(invar2);
173  *status = CASU_WARN;
174  return(CASU_WARN);
175  }
176 
177  /* Wrap the input mask into a cpl_mask structure and use it to set the
178  internal mask for each of the input images */
179 
180  inbpm = casu_mask_get_data(mask);
181  nx = casu_mask_get_size_x(mask);
182  ny = casu_mask_get_size_y(mask);
183  cplmask = cpl_mask_wrap((cpl_size)nx,(cpl_size)ny,(cpl_binary *)inbpm);
184  for (i = 0; i < nfiles2; i++)
185  cpl_image_reject_from_mask(casu_fits_get_image(inlist2[i]),cplmask);
186  cpl_mask_unwrap(cplmask);
187 
188  /* Do an initial sky combination */
189 
190  casu_imcombine(inlist2,invar2,nfiles2,1,1,0,2.0,"EXPTIME",&outim,&outimv,
191  &rejmask,&rejplus,&drs,status);
192  *skyout = casu_fits_wrap(outim,inlist2[0],NULL,NULL);
193  if (invar != NULL)
194  *skyvar = casu_fits_wrap(outimv,invar2[0],NULL,NULL);
195  freespace(rejmask);
196  freespace(rejplus);
197  freepropertylist(drs);
198 
199  /* Clean up any blank bits */
200 
201  (void)casu_inpaint(*skyout,nbsize,status);
202 
203  /* If this is the only iteration then get out of here now */
204 
205  if (niter == 0)
206  return(*status);
207 
208  /* Work out the median sky, ignoring the bad bits */
209 
210  medsky = casu_sky_med(*skyout);
211 
212  /* Get jitter offsets from wcs */
213 
214  casu_sky_joffs(inlist2,nfiles2,&xoffs,&yoffs);
215  mindx = xoffs[0];
216  mindy = yoffs[0];
217  for (i = 1; i < nfiles2; i++) {
218  mindx = min(mindx,xoffs[i]);
219  mindy = min(mindy,yoffs[i]);
220  }
221 
222  /* Do an initial subtraction */
223 
224  list_ss = cpl_malloc(nfiles2*sizeof(casu_fits *));
225  skyim = casu_fits_get_image(*skyout);
226  for (i = 0; i < nfiles2; i++) {
227  im = casu_fits_get_image(inlist2[i]);
228  newim = cpl_image_subtract_create(im,skyim);
229  cpl_image_add_scalar(newim,(double)medsky);
230  list_ss[i] = casu_fits_wrap(newim,inlist2[i],NULL,NULL);
231  }
232  casu_fits_delete(*skyout);
233  if (invar != NULL)
234  casu_fits_delete(*skyvar);
235 
236  /* Set up some counters and begin the iteration loop */
237 
238  nbad0 = 0;
239  lastone = 0;
240  for (iter = 1; iter <= niter; iter++) {
241  if (lastone)
242  break;
243  lastone = (iter == niter);
244 
245  /* Dither the sky subtracted input images */
246 
247  (void)casu_imdither(list_ss,&conf,nfiles2,1,5.0,5.0,&p,"EXPTIME",&dith,
248  &dithc,status);
249  cpl_propertylist_delete(p);
250 
251  /* How many dead pixels are there in the dithered image? */
252 
253  confdata = cpl_image_get_data_int(dithc);
254  npts = (int)cpl_image_get_size_x(dithc)*(int)cpl_image_get_size_y(dithc);
255  nbad_init = 0;
256  for (i = 0; i < npts; i++)
257  if (confdata[i] == 0)
258  nbad_init++;
259 
260  /* Get rid of the sky subtracted images */
261 
262  for (i = 0; i < nfiles2; i++)
263  casu_fits_delete(list_ss[i]);
264 
265  /* Wrap the result */
266 
267  dithf = casu_fits_wrap(dith,inlist2[0],NULL,NULL);
268  dithcf = casu_fits_wrap(dithc,conf,NULL,NULL);
269 
270  /* Now get an object mask from this dithered image */
271 
272  (void)casu_opm(dithf,dithcf,ipix,thresh,nbsize,smkern,2,status);
273 
274  /* How many flagged pixels are there, not counting the ones already
275  flagged in the confidence map */
276 
277  nbad = (int)cpl_image_count_rejected((const cpl_image *)dith) -
278  nbad_init;
279  dbad = nbad - nbad0;
280  fbad = (iter > 1 ? (float)abs(dbad)/(float)nbad0 : 10000.0);
281  cpl_msg_info(fctid,
282  "Iteration: %" CPL_SIZE_FORMAT ", Nreject: %" CPL_SIZE_FORMAT " %" CPL_SIZE_FORMAT,
283  (cpl_size)iter,(cpl_size)nbad,(cpl_size)nbad0);
284  if (fbad < 0.025 || dbad < 0) {
285  lastone = 1;
286  } else {
287  nbad0 = nbad;
288  }
289 
290  /* Allow the mask to grow before the next iteration */
291 
292  casu_sky_mask_grow(dith,2);
293 
294  /* Right, now decide which part of the mask belongs to each of the
295  input images and update the input mask. */
296 
297  dithmask = cpl_image_get_bpm(dith);
298  for (i = 0; i < nfiles2; i++) {
299  xx1 = (int)(-mindx + xoffs[i] + 1.5);
300  xx2 = xx1 + nx - 1;
301  yy1 = (int)(-mindy + yoffs[i] + 1.5);
302  yy2 = yy1 + ny - 1;
303  newmask = cpl_mask_extract(dithmask,(cpl_size)xx1,(cpl_size)yy1,
304  (cpl_size)xx2,(cpl_size)yy2);
305  curmask = cpl_image_get_bpm(casu_fits_get_image(inlist2[i]));
306  cpl_mask_or(curmask,newmask);
307  cpl_mask_delete(newmask);
308  }
309 
310  /* Delete the dither and its confidence map */
311 
312  casu_fits_delete(dithf);
313  casu_fits_delete(dithcf);
314 
315  /* Do a new sky combination using these new object masks */
316 
317  casu_imcombine(inlist2,invar2,nfiles2,1,1,0,2.0,"EXPTIME",&outim,
318  &outimv,&rejmask,&rejplus,&drs,status);
319  *skyout = casu_fits_wrap(outim,inlist2[0],NULL,NULL);
320  if (invar != NULL)
321  *skyvar = casu_fits_wrap(outimv,invar2[0],NULL,NULL);
322  freespace(rejmask);
323  freespace(rejplus);
324  freepropertylist(drs);
325  p = casu_fits_get_ehu(*skyout);
326  cpl_propertylist_update_string(p,"ESO DRS SKYALGO","pawsky_mask");
327  cpl_propertylist_set_comment(p,"ESO DRS SKYALGO",
328  "Sky estimation algorithm");
329 
330  /* Clean up any blank bits */
331 
332  (void)casu_inpaint(*skyout,nbsize,status);
333 
334  /* Do the sky subtraction again so long as this isn't
335  the last iteration */
336 
337  if (! lastone) {
338  skyim = casu_fits_get_image(*skyout);
339  for (i = 0; i < nfiles2; i++) {
340  im = casu_fits_get_image(inlist2[i]);
341  newim = cpl_image_subtract_create(im,skyim);
342  cpl_image_add_scalar(newim,(double)medsky);
343  list_ss[i] = casu_fits_wrap(newim,inlist2[i],NULL,NULL);
344  }
345  casu_fits_delete(*skyout);
346  if (invar != NULL)
347  casu_fits_delete(*skyvar);
348  }
349  }
350 
351  /* Free up some workspace that we've collected along the way */
352 
353  freespace(xoffs);
354  freespace(yoffs);
355  freespace(list_ss);
356  freespace(inlist2);
357  freespace(invar2);
358  return(*status);
359 }
360 
361 /*---------------------------------------------------------------------------*/
410 /*---------------------------------------------------------------------------*/
411 
412 extern int casu_pawsky_mask_pre(casu_fits **inlist, casu_fits **invar,
413  int nfiles, casu_mask *mask,
414  casu_fits *objmask, int nbsize,
415  casu_fits **skyout, casu_fits **skyvar,
416  int *status) {
417  const char *fctid = "casu_pawsky_mask_pre";
418  unsigned char *inbpm,*rejplus,*rejmask;
419  int nx,ny,npts,ncoor,i,j,nx_objmask,ny_objmask,k,kk,ix,iy,ind,*opm;
420  int nfiles2;
421  cpl_mask *cplmask;
422  cpl_wcs *wcs_objmask,*wcs;
423  cpl_matrix *in_xy,*out_xy,*ddx,*ddx_out;
424  cpl_image *im,*outim,*outimv;
425  cpl_propertylist *drs,*p;
426  double *inxy_data,xx,yy,*ddx_data,shiftx,shifty;
427  casu_fits **inlist2,**invar2;
428 
429  /* Inherited status */
430 
431  *skyout = NULL;
432  *skyvar = NULL;
433  if (*status != CASU_OK)
434  return(*status);
435 
436  /* If there aren't any images, then get out of here */
437 
438  if (nfiles == 0) {
439  cpl_msg_error(fctid,"Sky correction impossible. No science frames");
440  FATAL_ERROR
441  }
442 
443  /* Check to see which files are good */
444 
445  inlist2 = cpl_malloc(nfiles*sizeof(casu_fits *));
446  if (invar != NULL)
447  invar2 = cpl_malloc(nfiles*sizeof(casu_fits *));
448  else
449  invar2 = NULL;
450  nfiles2 = 0;
451  for (i = 0; i < nfiles; i++) {
452  if (casu_fits_get_status(inlist[i]) == CASU_OK) {
453  inlist2[nfiles2] = inlist[i];
454  if (invar != NULL)
455  invar2[nfiles2] = invar[i];
456  nfiles2++;
457  }
458  }
459 
460  /* If no good images are present then wrap a dummy image and return it */
461 
462  if (nfiles2 == 0) {
463  outim = casu_dummy_image(inlist[0]);
464  *skyout = casu_fits_wrap(outim,inlist[0],NULL,NULL);
466  casu_fits_set_status(*skyout,CASU_FATAL);
467  if (invar != NULL) {
468  outimv = casu_dummy_image(inlist[0]);
469  *skyvar = casu_fits_wrap(outimv,invar[0],NULL,NULL);
471  } else {
472  *skyvar = NULL;
473  }
474  cpl_msg_warning(fctid,"No good images in input list");
475  freespace(inlist2);
476  *status = CASU_WARN;
477  return(CASU_WARN);
478  }
479 
480  /* Wrap the input mask into a cpl_mask structure and use it to set the
481  internal mask for each of the input images */
482 
483  inbpm = casu_mask_get_data(mask);
484  nx = casu_mask_get_size_x(mask);
485  ny = casu_mask_get_size_y(mask);
486  cplmask = cpl_mask_wrap((cpl_size)nx,(cpl_size)ny,(cpl_binary *)inbpm);
487  for (i = 0; i < nfiles2; i++)
488  cpl_image_reject_from_mask(casu_fits_get_image(inlist2[i]),cplmask);
489  cpl_mask_unwrap(cplmask);
490 
491  /* Open the WCS of the object mask and get the pixel mask info */
492 
493  wcs_objmask = cpl_wcs_new_from_propertylist(casu_fits_get_ehu(objmask));
494  opm = cpl_image_get_data(casu_fits_get_image(objmask));
495  nx_objmask = cpl_image_get_size_x(casu_fits_get_image(objmask));
496  ny_objmask = cpl_image_get_size_y(casu_fits_get_image(objmask));
497 
498  /* Get some memory so that we can do a transformation between the coordinate
499  systems of the input frames and that of the object mask */
500 
501  npts = nx*ny;
502  ncoor = 2;
503  in_xy = cpl_matrix_new((cpl_size)npts,(cpl_size)ncoor);
504 
505  /* Initialise the data for the first x,y matrix */
506 
507  inxy_data = cpl_matrix_get_data(in_xy);
508  k = 0;
509  for (j = 0; j < ny; j++) {
510  for (i = 0; i < nx; i++) {
511  inxy_data[k++] = (double)(i+1);
512  inxy_data[k++] = (double)(j+1);
513  }
514  }
515 
516  /* Initialise data for an offset matrix */
517 
518  ddx = cpl_matrix_new(1,2);
519  ddx_data = cpl_matrix_get_data(ddx);
520  ddx_data[0] = 1.0;
521  ddx_data[1] = 1.0;
522 
523  /* Loop for each input file. Convert the xy matrix to an xy in the object
524  mask frame of reference for the first file. Then use the offsets between
525  the first image and the subsequent ones to define the location of
526  the object pixels in the following images */
527 
528  for (k = 0; k < nfiles2; k++) {
529  wcs = cpl_wcs_new_from_propertylist(casu_fits_get_ehu(inlist2[k]));
530  im = casu_fits_get_image(inlist2[k]);
531  if (k == 0)
532  casu_sky_xytoxy(wcs,wcs_objmask,in_xy,&out_xy);
533  casu_sky_xytoxy(wcs,wcs_objmask,ddx,&ddx_out);
534  cpl_wcs_delete(wcs);
535  shiftx = cpl_matrix_get(out_xy,0,0) - cpl_matrix_get(ddx_out,0,0);
536  shifty = cpl_matrix_get(out_xy,0,1) - cpl_matrix_get(ddx_out,0,1);
537  kk = 0;
538  for (j = 0; j < ny; j++) {
539  for (i = 0; i < nx; i++) {
540  xx = cpl_matrix_get(out_xy,kk,0) - shiftx;
541  yy = cpl_matrix_get(out_xy,kk,1) - shifty;
542  kk++;
543  ix = casu_nint(xx);
544  iy = casu_nint(yy);
545  if (ix < 1 || ix > nx_objmask || iy < 1 || iy > ny_objmask)
546  continue;
547  ind = (iy-1)*nx_objmask + ix - 1;
548  if (opm[ind])
549  cpl_image_reject(im,i+1,j+1);
550  }
551  }
552  cpl_matrix_delete(ddx_out);
553  }
554  cpl_matrix_delete(in_xy);
555  cpl_matrix_delete(out_xy);
556  cpl_wcs_delete(wcs_objmask);
557 
558  /* Do a sky combination */
559 
560  casu_imcombine(inlist2,invar2,nfiles2,1,1,0,2.0,"EXPTIME",&outim,&outimv,
561  &rejmask,&rejplus,&drs,status);
562  *skyout = casu_fits_wrap(outim,inlist2[0],NULL,NULL);
563  if (invar != NULL)
564  *skyvar = casu_fits_wrap(outimv,invar2[0],NULL,NULL);
565  freespace(rejmask);
566  freespace(rejplus);
567  freepropertylist(drs);
568  freespace(inlist2);
569  p = casu_fits_get_ehu(*skyout);
570  cpl_propertylist_update_string(p,"ESO DRS SKYALGO","pawsky_mask_pre");
571  cpl_propertylist_set_comment(p,"ESO DRS SKYALGO",
572  "Sky estimation algorithm");
573  cpl_propertylist_update_string(p,"ESO DRS MASKUSED",
574  casu_fits_get_filename(objmask));
575  cpl_propertylist_set_comment(p,"ESO DRS MASKUSED",
576  "Object masked used to make sky");
577 
578  /* Clean up any blank bits */
579 
580  (void)casu_inpaint(*skyout,nbsize,status);
581 
582  /* Get out of here */
583 
584  return(*status);
585 }
586 
587 /*---------------------------------------------------------------------------*/
641 /*---------------------------------------------------------------------------*/
642 
643 extern int casu_simplesky_mask(casu_fits **inlist, casu_fits **invar,
644  int nfiles, casu_fits *conf, casu_mask *mask,
645  casu_fits **skyout, casu_fits **skyvar,
646  int niter, int ipix, float thresh, int nbsize,
647  float smkern, int *status) {
648  const char *fctid = "casu_simplesky_mask";
649  unsigned char *inbpm,*rejmask,*rejplus;
650  int nx,ny,i,ninit,nbad0,iter,nbad,nb,dbad,lastone,nfiles2;
651  cpl_mask *cplmask,*newmask,*oldmask;
652  cpl_image *outim,*skyim,*im,*outimv;
653  cpl_propertylist *drs,*p;
654  casu_fits *skysub_im,**inlist2,**invar2;
655  float fbad,medsky;
656 
657  /* Inherited status */
658 
659  *skyout = NULL;
660  *skyvar = NULL;
661  if (*status != CASU_OK)
662  return(*status);
663 
664  /* If there aren't any images, then get out of here */
665 
666  if (nfiles == 0) {
667  cpl_msg_error(fctid,"Sky correction impossible. No science frames");
668  FATAL_ERROR
669  }
670 
671  /* Check to see which files are good */
672 
673  inlist2 = cpl_malloc(nfiles*sizeof(casu_fits *));
674  if (invar != NULL)
675  invar2 = cpl_malloc(nfiles*sizeof(casu_fits*));
676  else
677  invar2 = NULL;
678  nfiles2 = 0;
679  for (i = 0; i < nfiles; i++) {
680  if (casu_fits_get_status(inlist[i]) == CASU_OK) {
681  inlist2[nfiles2] = inlist[i];
682  if (invar != NULL)
683  invar2[nfiles2] = invar[i];
684  nfiles2++;
685  }
686  }
687 
688  /* If no good images are present then wrap a dummy image and return it */
689 
690  if (nfiles2 == 0) {
691  outim = casu_dummy_image(inlist[0]);
692  *skyout = casu_fits_wrap(outim,inlist[0],NULL,NULL);
694  casu_fits_set_status(*skyout,CASU_FATAL);
695  if (invar != NULL) {
696  outimv = casu_dummy_image(inlist[0]);
697  *skyvar = casu_fits_wrap(outimv,inlist[0],NULL,NULL);
699  } else {
700  *skyvar = NULL;
701  }
702  cpl_msg_warning(fctid,"No good images in input list");
703  freespace(inlist2);
704  *status = CASU_WARN;
705  return(CASU_WARN);
706  }
707 
708  /* Wrap the input mask into a cpl_mask structure and use it to set the
709  internal mask for each of the input images */
710 
711  inbpm = casu_mask_get_data(mask);
712  nx = casu_mask_get_size_x(mask);
713  ny = casu_mask_get_size_y(mask);
714  cplmask = cpl_mask_wrap((cpl_size)nx,(cpl_size)ny,(cpl_binary *)inbpm);
715  for (i = 0; i < nfiles2; i++)
716  cpl_image_reject_from_mask(casu_fits_get_image(inlist2[i]),cplmask);
717  cpl_mask_unwrap(cplmask);
718  ninit = cpl_image_count_rejected((const cpl_image *)casu_fits_get_image(inlist2[0]));
719 
720  /* Do an initial sky combination */
721 
722  casu_imcombine(inlist2,invar2,nfiles2,1,1,0,2.0,"EXPTIME",&outim,&outimv,
723  &rejmask,&rejplus,&drs,status);
724  *skyout = casu_fits_wrap(outim,inlist2[0],NULL,NULL);
725  if (invar != NULL)
726  *skyvar = casu_fits_wrap(outimv,invar2[0],NULL,NULL);
727  freespace(rejmask);
728  freespace(rejplus);
729  freepropertylist(drs);
730 
731  /* Clean up any blank bits */
732 
733  (void)casu_inpaint(*skyout,nbsize,status);
734 
735  /* If this is the only iteration then get out of here now */
736 
737  if (niter == 0)
738  return(*status);
739 
740  /* Begin the iteration loop */
741 
742  nbad0 = 0;
743  for (iter = 1; iter <= niter; iter++) {
744 
745  /* For each image, sky subtract using the latest sky. Then create
746  an object mask from the sky subtracted image and count the number
747  of bad pixels */
748 
749  skyim = casu_fits_get_image(*skyout);
750  medsky = casu_sky_med(*skyout);
751  nbad = 0;
752  for (i = 0; i < nfiles2; i++) {
753  im = casu_fits_get_image(inlist2[i]);
754  outim = cpl_image_subtract_create(im,skyim);
755  cpl_image_add_scalar(outim,(double)medsky);
756  skysub_im = casu_fits_wrap(outim,inlist2[i],NULL,NULL);
757  *status = CASU_OK;
758  (void)casu_opm(skysub_im,conf,ipix,thresh,nbsize,smkern,2,
759  status);
760  nb = (int)cpl_image_count_rejected((const cpl_image *)outim) -
761  ninit;
762  nbad += nb;
763  newmask = cpl_image_get_bpm(outim);
764  oldmask = cpl_image_get_bpm(im);
765  cpl_mask_or(oldmask,newmask);
766  freefits(skysub_im);
767  }
768 
769  /* Update report on the number of pixels rejected */
770 
771  dbad = nbad - nbad0;
772  fbad = (iter > 1 ? (float)abs(dbad)/(float)nbad0 : 10000.0);
773  cpl_msg_info(fctid,
774  "Iteration: %" CPL_SIZE_FORMAT ", Nreject: %" CPL_SIZE_FORMAT " %" CPL_SIZE_FORMAT,
775  (cpl_size)iter,(cpl_size)nbad,(cpl_size)nbad0);
776 
777  if (fbad < 0.025 || dbad < 0) {
778  lastone = 1;
779  } else {
780  nbad0 = nbad;
781  lastone = 0;
782  }
783 
784  /* If this has converged or this is the last iteration, then
785  get out of here now. */
786 
787  if (lastone || iter == niter) {
788  break;
789 
790  /* Otherwise, delete the current sky and create a new one */
791 
792  } else {
793  freefits(*skyout);
794  casu_imcombine(inlist2,invar2,nfiles2,1,1,0,2.0,"EXPTIME",&outim,
795  &outimv,&rejmask,&rejplus,&drs,status);
796  *skyout = casu_fits_wrap(outim,inlist2[0],NULL,NULL);
797  if (invar != NULL)
798  *skyvar = casu_fits_wrap(outimv,invar2[0],NULL,NULL);
799  (void)casu_inpaint(*skyout,nbsize,status);
800  freespace(rejmask);
801  freespace(rejplus);
802  freepropertylist(drs);
803  p = casu_fits_get_ehu(*skyout);
804  cpl_propertylist_update_string(p,"ESO DRS SKYALGO",
805  "simplesky_mask");
806  cpl_propertylist_set_comment(p,"ESO DRS SKYALGO",
807  "Sky estimation algorithm");
808  }
809  }
810  freespace(inlist2);
811  freespace(invar2);
812  return(*status);
813 }
814 
815 /*---------------------------------------------------------------------------*/
833 /*---------------------------------------------------------------------------*/
834 
835 static void casu_sky_mask_grow(cpl_image *dith, float rad) {
836  cpl_binary *inmap,*outmap;
837  int nx,ny,ir,i,j,indx,ixmin,ixmax,iymin,iymax,ii,jj,indx2;
838  float dx,dy,radius;
839 
840  /* Get the input map */
841 
842  inmap = cpl_mask_get_data(cpl_image_get_bpm(dith));
843  nx = (int)cpl_image_get_size_x(dith);
844  ny = (int)cpl_image_get_size_y(dith);
845 
846  /* Get an output map of the same size. Copy the input map to it */
847 
848  outmap = cpl_malloc(nx*ny*sizeof(*outmap));
849  memmove(outmap,inmap,nx*ny*sizeof(*inmap));
850 
851  /* What is the minimum cell size that we need to consider given the
852  input radius */
853 
854  ir = casu_nint(rad);
855 
856  /* Right, loop through the input image. If the current input pixel is
857  not flagged, then move on to the next one. If it is, then look at
858  a cell around it. Find all the pixels in that cell that are within
859  the grow radius and flag them */
860 
861  for (j = 0; j < ny; j++) {
862  for (i = 0; i < nx; i++) {
863  indx = j*nx + i;
864  if (inmap[indx] != 2)
865  continue;
866  ixmin = max(0,i-ir);
867  ixmax = min(nx-1,i+ir);
868  iymin = max(0,j-ir);
869  iymax = min(ny-1,j+ir);
870  for (jj = iymin; jj <= iymax; jj++) {
871  dy = (float)(jj - j);
872  for (ii = ixmin; ii <= ixmax; ii++) {
873  dx = (float)(ii - i);
874  radius = (float)sqrt(pow(dx,2.0) + pow(dy,2.0));
875  if (radius <= rad) {
876  indx2 = jj*nx + ii;
877  outmap[indx2] = 1;
878  }
879  }
880  }
881  }
882  }
883 
884  /* Now move the result back into the input mask. Free up workspace
885  and get out of here */
886 
887  memmove(inmap,outmap,nx*ny*sizeof(*inmap));
888  cpl_free(outmap);
889 }
890 
891 /*---------------------------------------------------------------------------*/
909 /*---------------------------------------------------------------------------*/
910 
911 static float casu_sky_med(casu_fits *sky) {
912  int npts;
913  float *data,med;
914  unsigned char *bpm;
915  cpl_image *skyim;
916 
917  /* Get the size of the data array */
918 
919  skyim = casu_fits_get_image(sky);
920  npts = (int)cpl_image_get_size_x(skyim)*(int)cpl_image_get_size_y(skyim);
921 
922  /* Get the data */
923 
924  data = cpl_image_get_data_float(skyim);
925  bpm = (unsigned char *)cpl_mask_get_data(cpl_image_get_bpm(skyim));
926 
927  /* Get the median */
928 
929  med = casu_med(data,bpm,(long)npts);
930  return(med);
931 }
932 
933 /*---------------------------------------------------------------------------*/
955 /*---------------------------------------------------------------------------*/
956 
957 static void casu_sky_joffs(casu_fits **inlist, int nfiles, float **xoffs,
958  float **yoffs) {
959  float xoff,yoff;
960  cpl_wcs *wcsref,*wcs;
961  int refset,i,status;
962  const double maxoffset = 12000;
963  casu_fits *ff;
964  const char *fctid = "casu_sky_joffs";
965 
966  /* Get a bit of workspace to hold the offsets */
967 
968  *xoffs = cpl_malloc(nfiles*sizeof(float));
969  *yoffs = cpl_malloc(nfiles*sizeof(float));
970 
971  /* Work out the jitter offsets from the WCS. First loop for each image */
972 
973  refset = 0;
974  wcsref = NULL;
975  for (i = 0; i < nfiles; i++) {
976  ff = inlist[i];
977  wcs = cpl_wcs_new_from_propertylist(casu_fits_get_ehu(ff));
978 
979  /* If we can't get a WCS for this image, then signal that with
980  a warning */
981 
982  if (wcs == NULL) {
983  cpl_msg_warning(fctid,"Unable to get WCS for %s",
985  (*xoffs)[i] = 0.0;
986  (*yoffs)[i] = 0.0;
987  casu_fits_set_error(ff,CASU_WARN);
988  continue;
989  }
990 
991  /* Define the reference wcs pointer and set the first offset to zero */
992 
993  if (! refset) {
994  (*xoffs)[0] = 0.0;
995  (*yoffs)[0] = 0.0;
996  refset = 1;
997  wcsref = wcs;
998  continue;
999  }
1000 
1001  /* Work out the x,y offset */
1002 
1003  status = CASU_OK;
1004  (void)casu_diffxywcs(wcs,wcsref,&xoff,&yoff,&status);
1005 
1006  /* Did it work? If not the set a warning status for this file */
1007 
1008  if (status != CASU_OK) {
1009  (*xoffs)[i] = 0.0;
1010  (*yoffs)[i] = 0.0;
1011  cpl_msg_warning(fctid,"Unable to WCS difference for %s",
1013  } else if (fabs((double)xoff) > maxoffset ||
1014  fabs((double)yoff) > maxoffset) {
1015  casu_fits_set_error(ff,CASU_FATAL);
1016  cpl_msg_error(fctid,"WCS offsets for %s are >%g: %g %g -- ignoring",
1017  casu_fits_get_filename(ff),maxoffset,xoff,yoff);
1018  } else {
1019  (*xoffs)[i] = xoff;
1020  (*yoffs)[i] = yoff;
1021  }
1022  cpl_wcs_delete(wcs);
1023  }
1024  if (wcsref != NULL)
1025  cpl_wcs_delete(wcsref);
1026 
1027  /* Write the results to the headers */
1028 
1029  for (i = 0; i < nfiles; i++) {
1030  ff = inlist[i];
1031  cpl_propertylist_update_double(casu_fits_get_ehu(ff),
1032  "ESO DRS XOFFDITHER",
1033  (double)(*xoffs)[i]);
1034  cpl_propertylist_update_double(casu_fits_get_ehu(ff),
1035  "ESO DRS YOFFDITHER",
1036  (double)(*yoffs)[i]);
1037  }
1038 }
1039 
1040 /*---------------------------------------------------------------------------*/
1062 /*---------------------------------------------------------------------------*/
1063 
1064 static void casu_sky_xytoxy(cpl_wcs *inwcs, cpl_wcs *outwcs,
1065  cpl_matrix *inxy, cpl_matrix **outxy) {
1066  cpl_matrix *radec;
1067  cpl_array *wstatus;
1068 
1069  /* Convert the input xy data to RA/Dec */
1070 
1071  cpl_wcs_convert(inwcs,inxy,&radec,&wstatus,CPL_WCS_PHYS2WORLD);
1072  cpl_array_delete(wstatus);
1073 
1074  /* Now convert the RA/Dec to the xy coordinates of the second image */
1075 
1076  cpl_wcs_convert(outwcs,radec,outxy,&wstatus,CPL_WCS_WORLD2PHYS);
1077  cpl_array_delete(wstatus);
1078  cpl_matrix_delete(radec);
1079 }
1080 
1083 /*
1084 
1085 $Log: casu_sky.c,v $
1086 Revision 1.2 2015/08/07 13:06:54 jim
1087 Fixed copyright to ESO
1088 
1089 Revision 1.1.1.1 2015/06/12 10:44:32 jim
1090 Initial import
1091 
1092 Revision 1.12 2015/04/30 12:07:43 jim
1093 raised the maximum offset to be used in pawsky_mask
1094 
1095 Revision 1.11 2015/03/03 10:48:11 jim
1096 Fixed some memory leaks
1097 
1098 Revision 1.10 2015/01/29 11:56:27 jim
1099 modified comments
1100 
1101 Revision 1.9 2015/01/09 12:13:15 jim
1102 *** empty log message ***
1103 
1104 Revision 1.8 2014/12/11 12:23:33 jim
1105 new version
1106 
1107 Revision 1.7 2014/04/09 11:08:21 jim
1108 Get rid of a couple of compiler moans
1109 
1110 Revision 1.6 2014/03/26 15:58:46 jim
1111 Uses floating point confidence
1112 
1113 Revision 1.5 2013/11/27 10:35:27 jim
1114 Fixed routines so that add the DRS SKYALGO header keyword
1115 
1116 Revision 1.4 2013/11/21 09:38:14 jim
1117 detabbed
1118 
1119 Revision 1.3 2013-10-24 09:26:28 jim
1120 traps for dummy input files and tries to remove them from the analysis
1121 
1122 Revision 1.2 2013-09-30 18:12:24 jim
1123 Added casu_simplesky_mask
1124 
1125 Revision 1.1.1.1 2013-08-27 12:07:48 jim
1126 Imported
1127 
1128 
1129 */
int casu_fits_get_status(casu_fits *p)
Definition: casu_fits.c:711
cpl_image * casu_fits_get_image(casu_fits *p)
Definition: casu_fits.c:436
char * casu_fits_get_filename(casu_fits *p)
Definition: casu_fits.c:646
void casu_fits_delete(casu_fits *p)
Definition: casu_fits.c:364
int casu_fits_set_error(casu_fits *p, int status)
Definition: casu_fits.c:747
casu_fits * casu_fits_wrap(cpl_image *im, casu_fits *model, cpl_propertylist *phu, cpl_propertylist *ehu)
Definition: casu_fits.c:883
void casu_fits_set_status(casu_fits *p, int status)
Definition: casu_fits.c:801
cpl_propertylist * casu_fits_get_ehu(casu_fits *p)
Definition: casu_fits.c:576
unsigned char * casu_mask_get_data(casu_mask *m)
Definition: casu_mask.c:544
int casu_mask_get_size_y(casu_mask *m)
Definition: casu_mask.c:498
int casu_mask_get_size_x(casu_mask *m)
Definition: casu_mask.c:475
int casu_imdither(casu_fits **inf, casu_fits **inconf, int nimages, int nconfs, float lthr, float hthr, cpl_propertylist **p, const char *expkey, cpl_image **out, cpl_image **outc, int *status)
Dither a set of jittered observations.
int casu_simplesky_mask(casu_fits **inlist, casu_fits **invar, int nfiles, casu_fits *conf, casu_mask *mask, casu_fits **skyout, casu_fits **skyvar, int niter, int ipix, float thresh, int nbsize, float smkern, int *status)
Work out a masked sky estimate from a jitter series with large offsets.
Definition: casu_sky.c:643
int casu_imcombine(casu_fits **fset, casu_fits **fsetv, int nfits, int combtype, int scaletype, int xrej, float thresh, const char *expkey, cpl_image **outimage, cpl_image **outvimage, unsigned char **rejmask, unsigned char **rejplus, cpl_propertylist **drs, int *status)
Stack images into a mean or median image with rejection.
int casu_pawsky_mask_pre(casu_fits **inlist, casu_fits **invar, int nfiles, casu_mask *mask, casu_fits *objmask, int nbsize, casu_fits **skyout, casu_fits **skyvar, int *status)
Work out a sky estimate from an input jitter series and a pre-existing object mask.
Definition: casu_sky.c:412
int casu_opm(casu_fits *infile, casu_fits *conf, int ipix, float threshold, int nbsize, float filtfwhm, int niter, int *status)
Generate an object mask from an input image.
Definition: casu_opm.c:90
int casu_inpaint(casu_fits *in, int nbsize, int *status)
Inpaint pixels or patches in a map.
Definition: casu_inpaint.c:83
int casu_pawsky_mask(casu_fits **inlist, casu_fits **invar, int nfiles, casu_fits *conf, casu_mask *mask, casu_fits **skyout, casu_fits **skyvar, int niter, int ipix, float thresh, int nbsize, float smkern, int *status)
Work out a masked sky estimate from an input jitter series.
Definition: casu_sky.c:110
float casu_med(float *data, unsigned char *bpm, long npts)
Definition: casu_stats.c:89
cpl_image * casu_dummy_image(casu_fits *model)
Create a dummy image of zeros based on a model.
Definition: casu_utils.c:533
void casu_dummy_property(cpl_propertylist *p)
Set dummy property keyword.
Definition: casu_utils.c:445
int casu_diffxywcs(cpl_wcs *wcs, cpl_wcs *wcsref, float *xoff, float *yoff, int *status)