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
57typedef 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
69typedef 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
86static void skyest(long npts, float *data, cpl_binary *bpm, float thresh,
87 float *skymed, float *skynoise);
88static void medcalc(usefulinfo *uinfo, float, float, int);
89static void meancalc(usefulinfo *uinfo, float, float, int);
90static void xclip_med(usefulinfo *uinfo, float thresh, int scaletype);
91static void xclip_mean(usefulinfo *uinfo, float thresh, int scaletype);
92
93static void tidy(usefulinfo *uinfo);
94
97/*---------------------------------------------------------------------------*/
163/*---------------------------------------------------------------------------*/
164
165extern 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
482static 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
698static 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
906static 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
1101static 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
1297static 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
1318static 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 $
1341Revision 1.3 2015/11/25 10:26:31 jim
1342replaced some hardcoded numbers with defines
1343
1344Revision 1.2 2015/08/07 13:06:54 jim
1345Fixed copyright to ESO
1346
1347Revision 1.1.1.1 2015/06/12 10:44:32 jim
1348Initial import
1349
1350Revision 1.8 2015/03/12 09:16:51 jim
1351Modified to remove some compiler moans
1352
1353Revision 1.7 2015/01/29 11:51:56 jim
1354modified comments
1355
1356Revision 1.6 2015/01/09 13:12:44 jim
1357Fixed little bug in output to outvimage
1358
1359Revision 1.5 2014/12/11 12:23:33 jim
1360new version
1361
1362Revision 1.4 2014/04/09 09:09:51 jim
1363Detabbed
1364
1365Revision 1.3 2014/03/26 15:43:49 jim
1366Modified to remove globals
1367
1368Revision 1.2 2013/11/21 09:38:13 jim
1369detabbed
1370
1371Revision 1.1.1.1 2013-08-27 12:07:48 jim
1372Imported
1373
1374
1375*/
1376
cpl_image * casu_fits_get_image(casu_fits *p)
Definition: casu_fits.c:436
cpl_propertylist * casu_fits_get_phu(casu_fits *p)
Definition: casu_fits.c:531
char * casu_fits_get_filename(casu_fits *p)
Definition: casu_fits.c:646
cpl_propertylist * casu_fits_get_ehu(casu_fits *p)
Definition: casu_fits.c:576
int casu_fits_get_nexten(casu_fits *p)
Definition: casu_fits.c:497
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