VIRCAM Pipeline  2.3.12
casu_imcombine.c
1 /* $Id: casu_imcombine.c,v 1.3 2015/11/25 10:26:31 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/11/25 10:26:31 $
24  * $Revision: 1.3 $
25  * $Name: $
26  */
27 
28 /* Includes */
29 
30 #ifdef HAVE_CONFIG_H
31 #include <config.h>
32 #endif
33 
34 #include <math.h>
35 #include <string.h>
36 #include <cpl.h>
37 
38 #include "catalogue/casu_utils.h"
39 #include "casu_stats.h"
40 #include "catalogue/casu_fits.h"
41 #include "casu_mods.h"
42 
43 /* Macro definitions */
44 
45 #define FATAL_ERR(_f,_a) {cpl_msg_error(_f,"%s",_a); tidy(&uinfo); *status = CASU_FATAL; return(*status);}
46 #define WARN_ERR(_f,_a) {cpl_msg_error(_f,"%s",_a); tidy(&uinfo); *status = CASU_WARN; return(CASU_WARN);}
47 #define INFO_ERR(_f,_a) {cpl_msg_info(_f,"%s",_a);}
48 #define MEDIANCALC 1
49 #define MEANCALC 2
50 #define SZBUF 1024
51 #define DATAMIN -65535.0
52 #define DATAMAX 65535.0
53 
54 /* Definition of litestruct which is used to hold useful information about
55  each of the input frames and their associated images */
56 
57 typedef struct {
58  casu_fits *frame;
59  float exptime;
60  float expfudge;
61  float skylevel;
62  float skynoise;
63  float skyfudge;
64  float skyrenorm;
65 } litestruct;
66 
67 /* Structure for carrying around useful information */
68 
69 typedef struct {
70  litestruct *fileptrs;
71  float **datas;
72  float **vars;
73  cpl_binary **masks;
74  float *odata;
75  float *ovdata;
76  cpl_binary *omask;
77  long npts;
78  int nf;
79  float oskylevel;
80  unsigned char *rmask;
81  unsigned char *rplus;
82 } usefulinfo;
83 
84 /* Static subroutine prototypes */
85 
86 static void skyest(long npts, float *data, cpl_binary *bpm, float thresh,
87  float *skymed, float *skynoise);
88 static void medcalc(usefulinfo *uinfo, float, float, int);
89 static void meancalc(usefulinfo *uinfo, float, float, int);
90 static void xclip_med(usefulinfo *uinfo, float thresh, int scaletype);
91 static void xclip_mean(usefulinfo *uinfo, float thresh, int scaletype);
92 
93 static void tidy(usefulinfo *uinfo);
94 
97 /*---------------------------------------------------------------------------*/
163 /*---------------------------------------------------------------------------*/
164 
165 extern int casu_imcombine(casu_fits **fset, casu_fits **fsetv, int nfits,
166  int combtype, int scaletype, int xrej, float thresh,
167  const char *expkey, cpl_image **outimage,
168  cpl_image **outvimage, unsigned char **rejmask,
169  unsigned char **rejplus, cpl_propertylist **drs,
170  int *status) {
171  int i,k,j,gotit;
172  long npts = 0, nx = -1, ny = -1; /* return value for cpl_image_get_size_x on error */
173  char msg[SZBUF];
174  float sumsky,sumsig,texp1,texp2,expfudge,skylevel,skynoise,oskynoise;
175  float *dat,*work,**datas,**vars,*odata,*ovdata,oskylevel;
176  litestruct *ff,*fileptrs = NULL;
177  cpl_image *im;
178  cpl_propertylist *plist_p;
179  cpl_binary **masks,*omask;
180  usefulinfo uinfo;
181  const char *ic_fctid = "casu_imcombine";
182 
183  /* Inherited status */
184 
185  *rejmask = NULL;
186  *rejplus = NULL;
187  *drs = NULL;
188  *outimage = NULL;
189  if (outvimage != NULL)
190  *outvimage = NULL;
191  if (*status != CASU_OK)
192  return(*status);
193 
194  /* Check that there are any files in the first place...*/
195 
196  if (nfits == 0)
197  WARN_ERR(ic_fctid,"No files to combine")
198 
199  /* Initialise the useful info structure */
200 
201  uinfo.fileptrs = NULL;
202  uinfo.datas = NULL;
203  uinfo.vars = NULL;
204  uinfo.masks = NULL;
205  uinfo.rmask = NULL;
206  uinfo.rplus = NULL;
207  uinfo.nf = nfits;
208 
209  /* Get some file structures */
210 
211  fileptrs = cpl_calloc(nfits,sizeof(litestruct));
212  uinfo.fileptrs = fileptrs;
213 
214  /* Get workspace for convenience arrays */
215 
216  datas = cpl_malloc(nfits*sizeof(float *));
217  uinfo.datas = datas;
218  if (fsetv != NULL) {
219  vars = cpl_malloc(nfits*sizeof(float *));
220  uinfo.vars = vars;
221  } else
222  vars = NULL;
223  npts = casu_getnpts(casu_fits_get_image(fset[0]));
224  uinfo.npts = npts;
225  for (k = 0; k < nfits; k++) {
226  datas[k] = cpl_malloc(npts*sizeof(float));
227  if (fsetv != NULL)
228  vars[k] = cpl_malloc(npts*sizeof(float));
229  }
230  masks = cpl_malloc(nfits*sizeof(cpl_binary *));
231  uinfo.masks = masks;
232 
233  /* Get pointers to the data arrays */
234 
235  for (k = 0; k < nfits; k++) {
236  im = casu_fits_get_image(fset[k]);
237  dat = cpl_image_get_data_float(im);
238  if (dat == NULL) {
239  snprintf(msg,SZBUF,"Failed to load data from extension %d in %s",
240  casu_fits_get_nexten(fset[k]),
241  casu_fits_get_filename(fset[k]));
242  FATAL_ERR(ic_fctid,msg)
243  }
244  for (i = 0; i < npts; i++)
245  datas[k][i] = dat[i];
246  masks[k] = cpl_mask_get_data(cpl_image_get_bpm(im));
247  if (fsetv != NULL) {
248  im = casu_fits_get_image(fsetv[k]);
249  dat = cpl_image_get_data_float(im);
250  if (dat == NULL) {
251  snprintf(msg,SZBUF,"Failed to load data from extension %d in %s",
252  casu_fits_get_nexten(fsetv[k]),
253  casu_fits_get_filename(fsetv[k]));
254  FATAL_ERR(ic_fctid,msg)
255  }
256  for (i = 0; i < npts; i++)
257  vars[k][i] = dat[i];
258  }
259  }
260 
261  /* Open each file in turn and fill in the necessary information. Start with
262  the file name...*/
263 
264  for (i = 0; i < nfits; i++) {
265  ff = fileptrs + i;
266  ff->frame = fset[i];
267 
268  /* If this is the first frame, then keep the size of the data
269  array for future reference */
270 
271  if (i == 0) {
272  nx = (long)cpl_image_get_size_x(casu_fits_get_image(fset[0]));
273  ny = (long)cpl_image_get_size_y(casu_fits_get_image(fset[0]));
274  npts = nx*ny;
275  }
276 
277  /* Get the header and the exposure time */
278 
279  if (strlen(expkey)) {
280  gotit = 0;
281  for (k = 0; k < 2; k++) {
282  if (k == 0)
283  plist_p = casu_fits_get_phu(ff->frame);
284  else
285  plist_p = casu_fits_get_ehu(ff->frame);
286  if (plist_p != NULL && cpl_propertylist_has(plist_p,expkey)) {
287  gotit = 1;
288  break;
289  }
290  }
291  if (gotit) {
292  texp2 = (float)cpl_propertylist_get_double(plist_p,expkey);
293  } else {
294  snprintf(msg,SZBUF,
295  "Couldn't get exposure time for %s - expkey = %s",
296  casu_fits_get_filename(ff->frame),expkey);
297  INFO_ERR(ic_fctid,msg);
298  texp2 = 1.0;
299  }
300  } else {
301  texp2 = 1.0;
302  }
303 
304  /* Set a few properties */
305 
306  ff->exptime = texp2;
307  texp1 = fileptrs->exptime;
308  expfudge = texp1/texp2;
309  ff->expfudge = expfudge;
310 
311  /* If scaling by relative exposure time, then do it now. NB: This
312  isn't necessary for the first file as all the others are scaled
313  relative to it */
314 
315  if (scaletype == 3 && i > 0) {
316  for (j = 0; j < npts; j++) {
317  datas[i][j] *= ff->expfudge;
318  if (vars != NULL)
319  vars[i][j] *= powf(ff->expfudge,2.0);
320  }
321  }
322 
323  /* Get the background estimate and noise */
324 
325  skyest(npts,datas[i],masks[i],thresh,&skylevel,&skynoise);
326  ff->skylevel = skylevel;
327  ff->skynoise = skynoise;
328  }
329 
330  /* Work out average background and noise. Then create background zeropoint
331  or scale factor, depending upon which was requested in the call */
332 
333  work = cpl_malloc((unsigned int)nfits*sizeof(float));
334  for (i = 0; i < nfits; i++)
335  work[i] = (fileptrs+i)->skylevel;
336  sumsky = casu_med(work,NULL,(long)nfits);
337  for (i = 0; i < nfits; i++)
338  work[i] = (fileptrs+i)->skynoise;
339  sumsig = casu_med(work,NULL,(long)nfits);
340  cpl_free(work);
341  switch (scaletype) {
342  case 1:
343  for (i = 0; i < nfits; i++)
344  (fileptrs+i)->skyfudge = sumsky - (fileptrs+i)->skylevel;
345  break;
346  case 2:
347  for (i = 0; i < nfits; i++)
348  (fileptrs+i)->skyfudge = sumsky/(fileptrs+i)->skylevel;
349  break;
350  case 3:
351  for (i = 0; i < nfits; i++)
352  (fileptrs+i)->skyfudge = sumsky - (fileptrs+i)->skylevel;
353  break;
354  default:
355  for (i = 0; i < nfits; i++)
356  (fileptrs+i)->skyfudge = 0.0;
357  break;
358  }
359 
360  /* Open an output image based on the first frame in the frameset */
361 
362  *outimage = cpl_image_new((cpl_size)nx,(cpl_size)ny,CPL_TYPE_FLOAT);
363  odata = cpl_image_get_data_float(*outimage);
364  uinfo.odata = odata;
365  if (fsetv != NULL) {
366  *outvimage = cpl_image_new((cpl_size)nx,(cpl_size)ny,CPL_TYPE_FLOAT);
367  ovdata = cpl_image_get_data_float(*outvimage);
368  } else {
369  ovdata = NULL;
370  }
371  uinfo.ovdata = ovdata;
372  omask = cpl_mask_get_data(cpl_image_get_bpm(*outimage));
373  uinfo.omask = omask;
374  if (*outimage == NULL || odata == NULL)
375  FATAL_ERR(ic_fctid,"Couldn't create output image")
376  *rejmask = cpl_calloc(npts,sizeof(*rejmask));
377  uinfo.rmask = *rejmask;
378  *rejplus = cpl_calloc(npts,sizeof(*rejplus));
379  uinfo.rplus = *rejplus;
380 
381  /* Now do the averaging/medianing */
382 
383  switch (combtype) {
384  case MEDIANCALC:
385  medcalc(&uinfo,thresh,sumsig,scaletype);
386  break;
387  case MEANCALC:
388  meancalc(&uinfo,thresh,sumsig,scaletype);
389  break;
390  }
391 
392  /* Do the extra clipping here if you want it */
393 
394  if (xrej) {
395 
396  /* First get sky background and sigma from output data */
397 
398  skyest(npts,odata,omask,thresh,&oskylevel,&oskynoise);
399  uinfo.oskylevel = oskylevel;
400 
401  /* Now loop for all the files subtract off the mean frame (suitably
402  scaled and zero pointed depending on what was done in the first
403  place) */
404 
405  for (i = 0; i < nfits; i++) {
406  ff = fileptrs + i;
407  ff->skyrenorm = ff->skylevel/oskylevel;
408  switch (scaletype) {
409  case 1:
410  for (k = 0; k < npts; k++)
411  datas[i][k] -= (odata[k] - oskylevel);
412  break;
413  case 2:
414  for (k = 0; k < npts; k++)
415  datas[i][k] -= (odata[k] - oskylevel)*ff->skyrenorm;
416  break;
417  case 3:
418  for (k = 0; k < npts; k++)
419  datas[i][k] -= (odata[k] - oskylevel);
420  break;
421  case 0:
422  for (k = 0; k < npts; k++)
423  datas[i][k] -= (odata[k] - oskylevel);
424  break;
425  }
426 
427  /* Re-estimate the noise for this image */
428 
429  skyest(npts,datas[i],masks[i],thresh,&skylevel,&skynoise);
430  ff->skynoise = skynoise;
431  }
432 
433  /* Now do the extra clip... */
434 
435  switch (combtype) {
436  case MEDIANCALC:
437  xclip_med(&uinfo,thresh,scaletype);
438  break;
439  case MEANCALC:
440  xclip_mean(&uinfo,thresh,scaletype);
441  break;
442  }
443  }
444 
445  /* Write provenance keywords */
446 
447  *drs = cpl_propertylist_new();
448  casu_prov(*drs,fset,nfits,1);
449 
450  /* Right, tidy and get out of here */
451 
452  tidy(&uinfo);
453  return(CASU_OK);
454 }
455 
456 /*---------------------------------------------------------------------------*/
480 /*---------------------------------------------------------------------------*/
481 
482 static void xclip_med(usefulinfo *uinfo, float thresh, int scaletype) {
483  int nf1,nf2,nfm,nrejmax,is_even,k,is_even2,nrej,nremain,nm,nmm,nplus;
484  int nminus,nn,j,nf;
485  cpl_binary **masks,*omask;
486  unsigned char *rmask,*rplus;
487  long npts,i;
488  float **work,**dork,value,cliplev,**datas,*odata,oskylevel,**vars;
489  float valv = 0.0 ,*ovdata;
490  litestruct *ff,*fileptrs;
491 
492  /* Dereference the information you need */
493 
494  fileptrs = uinfo->fileptrs;
495  datas = uinfo->datas;
496  vars = uinfo->vars;
497  masks = uinfo->masks;
498  odata = uinfo->odata;
499  ovdata = uinfo->ovdata;
500  omask = uinfo->omask;
501  npts = uinfo->npts;
502  nf = uinfo->nf;
503  oskylevel = uinfo->oskylevel;
504  rmask = uinfo->rmask;
505  rplus = uinfo->rplus;
506 
507  /* Get some workspace */
508 
509  work = cpl_malloc(4*sizeof(float *));
510  for (i = 0; i < 4; i++)
511  work[i] = cpl_malloc(nf*sizeof(float));
512  dork = cpl_malloc(2*sizeof(float *));
513  for (i = 0; i < 2; i++)
514  dork[i] = cpl_malloc(nf*sizeof(float));
515 
516  /* Loop for each input pixel now... */
517 
518  for (i = 0; i < npts; i++) {
519  if (omask[i])
520  continue;
521 
522  /* Scale or shift data */
523 
524  nn = 0;
525  switch (scaletype) {
526  case 0:
527  for (k = 0; k < nf; k++) {
528  if (masks[k][i])
529  continue;
530  ff = fileptrs + k;
531  work[0][nn] = datas[k][i];
532  work[1][nn] = ff->skynoise;
533  work[2][nn] = datas[k][i] + odata[i] - oskylevel;
534  if (vars != NULL)
535  work[3][nn] = vars[k][i];
536  nn++;
537  }
538  break;
539  case 1:
540  for (k = 0; k < nf; k++) {
541  if (masks[k][i])
542  continue;
543  ff = fileptrs + k;
544  work[0][nn] = datas[k][i] + ff->skyfudge;
545  work[1][nn] = ff->skynoise;
546  work[2][nn] = datas[k][i] + odata[i] - oskylevel +
547  ff->skyfudge;
548  if (vars != NULL)
549  work[3][nn] = vars[k][i];
550  nn++;
551  }
552  break;
553  case 2:
554  for (k = 0; k < nf; k++) {
555  if (masks[k][i])
556  continue;
557  ff = fileptrs + k;
558  work[0][nn] = datas[k][i]*ff->skyfudge;
559  work[1][nn] = ff->skynoise*ff->skyfudge;
560  work[2][nn] = (datas[k][i] + odata[i]*ff->skyrenorm -
561  ff->skylevel)*ff->skyfudge;
562  if (vars != NULL)
563  work[3][nn] = vars[k][i]*powf(ff->skyfudge,2.0);
564  nn++;
565  }
566  break;
567  case 3:
568  for (k = 0; k < nf; k++) {
569  if (masks[k][i])
570  continue;
571  ff = fileptrs + k;
572  work[0][nn] = datas[k][i] + ff->skyfudge;
573  work[1][nn] = ff->skynoise;
574  work[2][nn] = datas[k][i] + odata[i] - oskylevel +
575  ff->skyfudge;
576  if (vars != NULL)
577  work[3][nn] = vars[k][i];
578  nn++;
579  }
580  break;
581  }
582 
583  /* Set up a few useful variables */
584 
585  nf1 = nn/2 - 1;
586  nf2 = nf1 + 1;
587  nfm = (nn + 1)/2 - 1;
588  nrejmax = nn/2;
589  is_even = !(nn & 1);
590 
591  /* Sort and get a first pass median */
592 
593  casu_sort(work,nn,4);
594  if (is_even)
595  value = 0.5*(work[0][nf1] + work[0][nf2]);
596  else
597  if (nn < 5)
598  value = work[0][nfm];
599  else
600  value = 0.25*(work[0][nfm-1] + work[0][nfm+1]) + 0.5*work[0][nfm];
601  if (vars != NULL) {
602  valv = 0.0;
603  for (j = 0; j < nn; j++)
604  valv += work[3][j];
605  valv *= CPL_MATH_PI_2/powf((float)nn,2.0);
606  }
607 
608  /* Do clipping */
609 
610  nplus = 0;
611  cliplev = value + thresh*work[1][nn-1];
612  while (nplus < nrejmax && work[0][nn-nplus-1] > cliplev)
613  nplus++;
614  nminus = 0;
615  cliplev = value - thresh*work[1][nn-1];
616  while ((nplus+nminus) < nrejmax && work[0][nminus] < cliplev)
617  nminus++;
618  nrej = nplus + nminus;
619 
620  /* If there were any clipped out, the re-estimate the value */
621 
622  if (nrej > 0) {
623  nremain = nn - nrej;
624  if (nremain != 0) {
625  nm = nremain/2 - 1;
626  for (j = 0; j < nremain; j++) {
627  dork[0][j] = work[2][j+nminus];
628  dork[1][j] = work[3][j+nminus];
629  }
630  nmm = (nremain + 1)/2 - 1;
631  is_even2 = !(nremain & 1);
632  casu_sort(dork,nm,2);
633  if (is_even2)
634  value = 0.5*(dork[0][nm] + dork[0][nm+1]);
635  else
636  if (nremain < 3)
637  value = dork[0][nmm];
638  else
639  value = 0.5*dork[0][nmm] + 0.25*(dork[0][nmm-1] +
640  dork[0][nmm+1]);
641  if (vars != NULL) {
642  valv = 0.0;
643  for (j = 0; j < nremain; j++)
644  valv += dork[1][j];
645  valv *= CPL_MATH_PI_2/powf((float)nremain,2.0);
646  }
647  }
648 
649  /* Store the result away */
650 
651  odata[i] = value;
652  if (vars != NULL)
653  ovdata[i] = valv;
654  rmask[i] = min(255,nrej);
655  rplus[i] = min(255,nplus);
656  } else {
657  rmask[i] = 0;
658  rplus[i] = 0;
659  }
660  }
661 
662  /* Ditch workspace and get out of here */
663 
664  for (i = 0; i < 4; i++)
665  cpl_free(work[i]);
666  cpl_free(work);
667  for (i = 0; i < 2; i++)
668  cpl_free(dork[i]);
669  cpl_free(dork);
670 }
671 
672 /*---------------------------------------------------------------------------*/
696 /*---------------------------------------------------------------------------*/
697 
698 static void xclip_mean(usefulinfo *uinfo, float thresh, int scaletype) {
699  int k,nf2,nrej,nplus,kk,krem,nf;
700  float *work[4],value,value2,nrejmax,resid,maxresid,**datas,*odata;
701  float oskylevel,**vars,valv = 0.0 ,valv2,*ovdata;
702  cpl_binary **masks,*omask;
703  long i,nn,npts;
704  litestruct *ff,*fileptrs;
705  unsigned char *iflag,*rmask,*rplus;
706 
707  /* Dereference the information you need */
708 
709  fileptrs = uinfo->fileptrs;
710  datas = uinfo->datas;
711  vars = uinfo->vars;
712  masks = uinfo->masks;
713  odata = uinfo->odata;
714  ovdata = uinfo->ovdata;
715  omask = uinfo->omask;
716  npts = uinfo->npts;
717  nf = uinfo->nf;
718  oskylevel = uinfo->oskylevel;
719  rmask = uinfo->rmask;
720  rplus = uinfo->rplus;
721 
722  /* Get some workspace */
723 
724  for (i = 0; i < 4; i++)
725  work[i] = cpl_malloc(nf*sizeof(float));
726  iflag = cpl_malloc(nf*sizeof(unsigned char));
727 
728  /* Loop for each input pixel now... */
729 
730  nrejmax = nf/2;
731  for (i = 0; i < npts; i++) {
732  if (omask[i])
733  continue;
734 
735  /* Scale or shift data */
736 
737  nn = 0;
738  switch (scaletype) {
739  case 0:
740  for (k = 0; k < nf; k++) {
741  if (masks[k][i])
742  continue;
743  ff = fileptrs + k;
744  work[0][nn] = datas[k][i];
745  work[1][nn] = ff->skynoise;
746  work[2][nn] = datas[k][i] + odata[i] - oskylevel;
747  if (vars != NULL)
748  work[3][nn] = vars[k][i];
749  iflag[nn++] = 0;
750  }
751  break;
752  case 1:
753  for (k = 0; k < nf; k++) {
754  if (masks[k][i])
755  continue;
756  ff = fileptrs + k;
757  work[0][nn] = datas[k][i] + ff->skyfudge;
758  work[1][nn] = ff->skynoise;
759  work[2][nn] = datas[k][i] + odata[i] - oskylevel + ff->skyfudge;
760  if (vars != NULL)
761  work[3][nn] = vars[k][i];
762  iflag[nn++] = 0;
763  }
764  break;
765  case 2:
766  for (k = 0; k < nf; k++) {
767  if (masks[k][i])
768  continue;
769  ff = fileptrs + k;
770  work[0][nn] = datas[k][i]*ff->skyfudge;
771  work[1][nn] = ff->skynoise*ff->skyfudge;
772  work[2][nn] = (datas[k][i] + odata[i]*ff->skyrenorm -
773  ff->skylevel)*ff->skyfudge;
774  if (vars != NULL)
775  work[3][nn] = vars[k][i]*powf(ff->skyfudge,2.0);
776  iflag[nn++] = 0;
777  }
778  break;
779  case 3:
780  for (k = 0; k < nf; k++) {
781  if (masks[k][i])
782  continue;
783  ff = fileptrs + k;
784  work[0][nn] = datas[k][i] + ff->skyfudge;
785  work[1][nn] = ff->skynoise;
786  work[2][nn] = datas[k][i] + odata[i] - oskylevel + ff->skyfudge;
787  if (vars != NULL)
788  work[3][nn] = vars[k][i];
789  iflag[nn++] = 0;
790  }
791  break;
792  }
793 
794  /* Get a first pass mean */
795 
796  value = 0.0;
797  for (k = 0; k < nn; k++)
798  value += work[0][k];
799  value /= (float)nn;
800  if (vars != NULL) {
801  valv = 0.0;
802  for (k = 0; k < nn; k++)
803  valv += work[3][k];
804  valv /= powf((float)nn,2.0);
805  }
806 
807  /* Enter a rejection loop. Reject pixels one at a time */
808 
809  nplus = 0;
810  nrej = 0;
811  for (kk = 0; kk < nrejmax; kk++) {
812  maxresid = -1.0e30;
813  krem = -1;
814  for (k = 0; k < nn; k++) {
815  if (iflag[k] == 1)
816  continue;
817  resid = fabs(work[0][k] - value);
818  if (resid > thresh*work[1][k]) {
819  if (nf <= 2)
820  resid = work[0][k] - value;
821  if (resid > maxresid) {
822  krem = k;
823  maxresid = resid;
824  }
825  }
826  }
827 
828  /* No further rejections */
829 
830  if (krem == -1)
831  break;
832 
833  /* Another pixel is rejected. If it's positive count it */
834 
835  iflag[krem] = 1;
836  if ((work[0][krem] - value) > 0.0)
837  nplus++;
838  nrej++;
839 
840  /* Re-evaluate the mean */
841 
842  nf2 = 0;
843  value2 = 0.0;
844  valv2 = 0.0;
845  for (k = 0; k < nn; k++) {
846  if (iflag[k] == 0) {
847  value2 += work[0][k];
848  if (vars != NULL)
849  valv2 += work[3][k];
850  nf2++;
851  }
852  }
853  if (nf2 != 0) {
854  value = value2/(float)nf2;
855  if (vars != NULL)
856  valv = valv2/powf((float)nf2,2.0);
857  } else
858  break;
859  }
860 
861  /* If there were any clipped out store the new value */
862 
863  if (nrej > 0) {
864  odata[i] = value;
865  if (vars != NULL)
866  ovdata[i] = valv;
867  }
868  rmask[i] = min(255,nrej);
869  rplus[i] = min(255,nplus);
870  }
871 
872  /* Ditch workspace and get out of here */
873 
874  for (k = 0; k < 4; k++)
875  cpl_free(work[k]);
876  cpl_free(iflag);
877 }
878 
879 /*---------------------------------------------------------------------------*/
904 /*---------------------------------------------------------------------------*/
905 
906 static void medcalc(usefulinfo *uinfo, float thresh, float avskynoise,
907  int scaletype) {
908  int nf1,nf2,nfm,nrejmax,is_even,nrej,nremain,nm,nmm,is_even2,k,nminus;
909  int nplus,nn,nf;
910  long i,npts,j;
911  float value,cliplev,*work[2],**datas,*odata,**vars, valv = 0.0,*ovdata;
912  litestruct *fileptrs;
913  cpl_binary **masks,*omask;
914  unsigned char *rmask,*rplus;
915 
916  /* Dereference the information you need */
917 
918  fileptrs = uinfo->fileptrs;
919  datas = uinfo->datas;
920  vars = uinfo->vars;
921  masks = uinfo->masks;
922  odata = uinfo->odata;
923  ovdata = uinfo->ovdata;
924  omask = uinfo->omask;
925  npts = uinfo->npts;
926  nf = uinfo->nf;
927  rmask = uinfo->rmask;
928  rplus = uinfo->rplus;
929 
930  /* Get a workspace */
931 
932  work[0] = cpl_malloc(nf*sizeof(float));
933  work[1] = cpl_malloc(nf*sizeof(float));
934 
935  /* Ok, loop for each pixel... */
936 
937  for (i = 0; i < npts; i++) {
938 
939  /* Scale or shift data */
940 
941  nn = 0;
942  switch (scaletype) {
943  case 0:
944  for (k = 0; k < nf; k++) {
945  if (masks[k][i])
946  continue;
947  work[0][nn] = datas[k][i];
948  if (vars != NULL)
949  work[1][nn] = vars[k][i];
950  nn++;
951  }
952  break;
953  case 1:
954  for (k = 0; k < nf; k++) {
955  if (masks[k][i])
956  continue;
957  work[0][nn] = datas[k][i] + (fileptrs+k)->skyfudge;
958  if (vars != NULL)
959  work[1][nn] = vars[k][i];
960  nn++;
961  }
962  break;
963  case 2:
964  for (k = 0; k < nf; k++) {
965  if (masks[k][i])
966  continue;
967  work[0][nn] = datas[k][i]*(fileptrs+k)->skyfudge;
968  if (vars != NULL)
969  work[1][nn] = vars[k][i]*pow((fileptrs+k)->skyfudge,2.0);
970  nn++;
971  }
972  break;
973  case 3:
974  for (k = 0; k < nf; k++) {
975  if (masks[k][i])
976  continue;
977  work[0][nn] = datas[k][i] + (fileptrs+k)->skyfudge;
978  if (vars != NULL)
979  work[1][nn] = vars[k][i];
980  nn++;
981  }
982  break;
983  }
984 
985  /* If nothing is available, then flag the output pixel */
986 
987  if (nn == 0) {
988  odata[i] = 0.0;
989  if (vars != NULL)
990  ovdata[i] = 0.0;
991  omask[i] = 1;
992  rmask[i] = 0;
993  rplus[i] = 0;
994  continue;
995  }
996 
997  /* Set up a few useful variables */
998 
999  nf1 = nn/2 - 1;
1000  nf2 = nf1 + 1;
1001  nfm = (nn + 1)/2 - 1;
1002  nrejmax = nn/2;
1003  is_even = !(nn & 1);
1004 
1005  /* Sort data and get the median */
1006 
1007  casu_sort(work,nn,2);
1008  if (is_even)
1009  value = 0.5*(work[0][nf1] + work[0][nf2]);
1010  else
1011  if (nn < 5)
1012  value = work[0][nfm];
1013  else
1014  value = 0.25*(work[0][nfm-1] + work[0][nfm+1]) +
1015  0.5*work[0][nfm];
1016  if (vars != NULL) {
1017  valv = 0.0;
1018  for (j = 0; j < nn; j++)
1019  valv += work[1][j];
1020  valv = CPL_MATH_PI_2*valv/powf((float)nn,2);
1021  }
1022 
1023  /* Enter a rejection loop */
1024 
1025  nplus = 0;
1026  cliplev = value + thresh*avskynoise;
1027  while (nplus < nrejmax && work[0][nn-nplus-1] > cliplev)
1028  nplus++;
1029  nminus = 0;
1030  cliplev = value - thresh*avskynoise;
1031  while ((nplus+nminus) < nrejmax && work[0][nminus] < cliplev)
1032  nminus++;
1033  nrej = nplus + nminus;
1034 
1035  /* If you've clipped any, then recalculate the median...*/
1036 
1037  if (nrej > 0) {
1038  nremain = nn - nrej;
1039  nm = nremain/2 - 1 + nminus;
1040  nmm = (nremain + 1)/2 - 1 + nminus;
1041  is_even2 = !(nremain & 1);
1042  if (is_even2)
1043  value = 0.5*(work[0][nm] + work[0][nm+1]);
1044  else
1045  if (nremain < 3)
1046  value = work[0][nmm];
1047  else
1048  value = 0.5*work[0][nmm] + 0.25*(work[0][nmm-1] +
1049  work[0][nmm+1]);
1050  if (vars != NULL) {
1051  valv = 0.0;
1052  for (j = 0; j < nremain; j++)
1053  valv += work[1][j];
1054  valv = CPL_MATH_PI_2*valv/powf((float)nn,2);
1055  }
1056  }
1057 
1058  /* Store the result away */
1059 
1060  odata[i] = value;
1061  if (vars != NULL)
1062  ovdata[i] = valv;
1063  omask[i] = 0;
1064  rmask[i] = min(255,nrej);
1065  rplus[i] = min(255,nplus);
1066  }
1067 
1068  /* Get rid of workspace */
1069 
1070  cpl_free(work[0]);
1071  cpl_free(work[1]);
1072 }
1073 
1074 /*---------------------------------------------------------------------------*/
1099 /*---------------------------------------------------------------------------*/
1100 
1101 static void meancalc(usefulinfo *uinfo, float thresh, float avskynoise,
1102  int scaletype) {
1103  int nf2,k,nrej,nplus,nrejmax,kk,krem,nf;
1104  long i,nn,npts;
1105  float *work[2],value,value2,maxresid,resid,fresid,cliplev,**datas,*odata;
1106  float **vars,valv,valv2,*ovdata;
1107  cpl_binary **masks,*omask;
1108  unsigned char *iflag,*rmask,*rplus;
1109  litestruct *fileptrs;
1110 
1111  /* Dereference the information you need */
1112 
1113  fileptrs = uinfo->fileptrs;
1114  datas = uinfo->datas;
1115  vars = uinfo->vars;
1116  masks = uinfo->masks;
1117  odata = uinfo->odata;
1118  ovdata = uinfo->ovdata;
1119  omask = uinfo->omask;
1120  npts = uinfo->npts;
1121  nf = uinfo->nf;
1122  rmask = uinfo->rmask;
1123  rplus = uinfo->rplus;
1124 
1125  /* Get vectors for workspace */
1126 
1127  work[0] = cpl_malloc(nf*sizeof(float));
1128  work[1] = cpl_malloc(nf*sizeof(float));
1129  iflag = cpl_malloc(nf*sizeof(unsigned char));
1130 
1131  /* Ok, loop for each pixel... */
1132 
1133  cliplev = thresh*avskynoise;
1134  for (i = 0; i < npts; i++) {
1135 
1136  /* Scale or shift data */
1137 
1138  nn = 0;
1139  switch (scaletype) {
1140  case 0:
1141  for (k = 0; k < nf; k++) {
1142  if (masks[k][i])
1143  continue;
1144  work[0][nn] = datas[k][i];
1145  if (vars != NULL)
1146  work[1][nn] = vars[k][i];
1147  nn++;
1148  }
1149  break;
1150  case 1:
1151  for (k = 0; k < nf; k++) {
1152  if (masks[k][i])
1153  continue;
1154  work[0][nn] = datas[k][i] + (fileptrs+k)->skyfudge;
1155  if (vars != NULL)
1156  work[1][nn] = vars[k][i];
1157  nn++;
1158  }
1159  break;
1160  case 2:
1161  for (k = 0; k < nf; k++) {
1162  if (masks[k][i])
1163  continue;
1164  work[0][nn] = datas[k][i]*(fileptrs+k)->skyfudge;
1165  if (vars != NULL)
1166  work[1][nn] = vars[k][i]*powf((fileptrs+k)->skyfudge,2.0);
1167  nn++;
1168  }
1169  break;
1170  case 3:
1171  for (k = 0; k < nf; k++) {
1172  if (masks[k][i])
1173  continue;
1174  work[0][nn] = datas[k][i] + (fileptrs+k)->skyfudge;
1175  if (vars != NULL)
1176  work[1][nn] = vars[k][i]*powf((fileptrs+k)->skyfudge,2.0);
1177  nn++;
1178  }
1179  break;
1180  }
1181 
1182  /* If nothing is available, then flag the output pixel */
1183 
1184  if (nn == 0) {
1185  odata[i] = 0.0;
1186  if (vars != NULL)
1187  ovdata[i] = 0.0;
1188  omask[i] = 1;
1189  rmask[i] = 0;
1190  rplus[i] = 0;
1191  continue;
1192  }
1193 
1194  /* Get the mean */
1195 
1196  value = 0.0;
1197  valv = 0.0;
1198  for (k = 0; k < nn; k++) {
1199  value += work[0][k];
1200  valv += work[1][k];
1201  iflag[k] = 0;
1202  }
1203  value /= (float)nn;
1204  valv /= powf((float)nn,2.0);
1205 
1206  /* Enter a rejection loop */
1207 
1208  nrejmax = nn - 1;
1209  nplus = 0;
1210  nf2 = 0;
1211  for (kk = 0; kk < nrejmax; kk++) {
1212  maxresid = -1.0e30;
1213  krem = -1;
1214  for (k = 0; k < nn; k++) {
1215  if (iflag[k] == 1)
1216  continue;
1217  resid = work[0][k] - value;
1218  fresid = (float)fabs((double)resid);
1219  if (fresid > cliplev) {
1220  if (nn <= 2)
1221  fresid = work[0][k] - value;
1222  if (fresid > maxresid) {
1223  krem = k;
1224  maxresid = fresid;
1225  }
1226  }
1227  }
1228  if (krem == -1)
1229  break;
1230  if ((work[0][krem] - value) > 0.0)
1231  nplus++;
1232  value2 = 0.0;
1233  valv2 = 0.0;
1234  iflag[krem] = 1;
1235  nf2 = 0;
1236  for (k = 0; k < nn; k++) {
1237  if (iflag[k] == 0) {
1238  value2 += work[0][k];
1239  valv2 += work[1][k];
1240  nf2 += 1;
1241  }
1242  }
1243  value = value2/(float)nf2;
1244  valv = valv2/powf((float)nf2,2.0);
1245  }
1246 
1247  /* If you've clipped any, then recalculate the mean...*/
1248 
1249  nrej = nn - nf2;
1250 
1251  /* Store the result away */
1252 
1253  odata[i] = value;
1254  if (vars != NULL)
1255  ovdata[i] = valv;
1256  omask[i] = 0;
1257  rmask[i] = min(255,nrej);
1258  rplus[i] = min(255,nplus);
1259  }
1260 
1261  /* Get rid of workspace */
1262 
1263  cpl_free(work[0]);
1264  cpl_free(work[1]);
1265  cpl_free(iflag);
1266 }
1267 
1268 /*---------------------------------------------------------------------------*/
1295 /*---------------------------------------------------------------------------*/
1296 
1297 static void skyest(long npts, float *data, cpl_binary *mask, float thresh,
1298  float *skymed, float *skynoise) {
1299  unsigned char *bpm;
1300 
1301  /* Set up the bad pixel mask */
1302 
1303  bpm = (unsigned char *)mask;
1304 
1305  /* Get the stats */
1306 
1307  casu_qmedsig(data,bpm,npts,thresh,3,DATAMIN,DATAMAX,skymed,
1308  skynoise);
1309 
1310 }
1311 
1312 /*---------------------------------------------------------------------------*/
1316 /*---------------------------------------------------------------------------*/
1317 
1318 static void tidy(usefulinfo *uinfo) {
1319  int i;
1320 
1321  /* Free up work space associated with file structures */
1322 
1323  freespace(uinfo->fileptrs);
1324  for (i = 0; i < uinfo->nf; i++)
1325  freespace(uinfo->datas[i]);
1326  if (uinfo->vars != NULL) {
1327  for (i = 0; i < uinfo->nf; i++)
1328  freespace(uinfo->vars[i]);
1329  }
1330  freespace(uinfo->datas);
1331  freespace(uinfo->vars);
1332  freespace(uinfo->masks);
1333 }
1334 
1338 /*
1339 
1340 $Log: casu_imcombine.c,v $
1341 Revision 1.3 2015/11/25 10:26:31 jim
1342 replaced some hardcoded numbers with defines
1343 
1344 Revision 1.2 2015/08/07 13:06:54 jim
1345 Fixed copyright to ESO
1346 
1347 Revision 1.1.1.1 2015/06/12 10:44:32 jim
1348 Initial import
1349 
1350 Revision 1.8 2015/03/12 09:16:51 jim
1351 Modified to remove some compiler moans
1352 
1353 Revision 1.7 2015/01/29 11:51:56 jim
1354 modified comments
1355 
1356 Revision 1.6 2015/01/09 13:12:44 jim
1357 Fixed little bug in output to outvimage
1358 
1359 Revision 1.5 2014/12/11 12:23:33 jim
1360 new version
1361 
1362 Revision 1.4 2014/04/09 09:09:51 jim
1363 Detabbed
1364 
1365 Revision 1.3 2014/03/26 15:43:49 jim
1366 Modified to remove globals
1367 
1368 Revision 1.2 2013/11/21 09:38:13 jim
1369 detabbed
1370 
1371 Revision 1.1.1.1 2013-08-27 12:07:48 jim
1372 Imported
1373 
1374 
1375 */
1376 
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
cpl_propertylist * casu_fits_get_phu(casu_fits *p)
Definition: casu_fits.c:531
int casu_fits_get_nexten(casu_fits *p)
Definition: casu_fits.c:497
cpl_propertylist * casu_fits_get_ehu(casu_fits *p)
Definition: casu_fits.c:576
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.
float casu_med(float *data, unsigned char *bpm, long npts)
Definition: casu_stats.c:89
void casu_qmedsig(float *data, unsigned char *bpm, long npts, float thresh, int niter, float lowv, float highv, float *median, float *sigma)
Definition: casu_stats.c:258
void casu_prov(cpl_propertylist *p, casu_fits **inlist, int n, int isextn)
Write provenance keywords.
Definition: casu_utils.c:287
long casu_getnpts(cpl_image *in)
Get the number of pixels in a 2d image.
Definition: casu_utils.c:243
void casu_sort(float **a, int n, int m)
Sort a 2d array by the first column and co-sort the rest.
Definition: casu_utils.c:349