VIRCAM Pipeline 2.3.15
casu_photcal_extinct.c
1/* $Id: casu_photcal_extinct.c,v 1.7 2015/09/30 08:33:06 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/09/30 08:33:06 $
24 * $Revision: 1.7 $
25 * $Name: $
26 */
27
28/* Includes */
29
30#ifdef HAVE_CONFIG_H
31#include <config.h>
32#endif
33
34#define _XOPEN_SOURCE
35#include <cpl.h>
36#include <math.h>
37#include <string.h>
38
39#include "casu_mods.h"
40#include "catalogue/casu_utils.h"
41#include "casu_stats.h"
42#include "catalogue/casu_fits.h"
43
44typedef struct {
45 char *filter_name;
46 float atm_extcoef;
47 float mag_offset;
48 char **coleq_columns;
49 char **coleq_errcols;
50 float *coleq_coefs;
51 float gal_extcoef;
52 float default_zp;
53 float default_zp_err;
54 int ncolumns_coleq;
55} photstrct;
56
57#define INITALLOC 1024
58#define SZBUF 1024
59#define DEGRAD (CPL_MATH_PI/180.0)
60#define RADARCSEC (3600.0*180.0/CPL_MATH_PI)
61
62static double pixsize (cpl_propertylist *plist);
63static int casu_phot_open(cpl_table *phottab, char *filt, photstrct *p);
64static void casu_phot_close(photstrct *p);
65static int extract_columns(cpl_table *tab, photstrct *p);
66static int extract_coleq(cpl_table *tab, photstrct *p);
67static void write_hdr_1(cpl_propertylist *p, int nresim, float med3, float sig3,
68 float lim3, float med5, float sig5, float lim5,
69 float extcoef, float extinct, float skybrt, int doqc);
70static void modifytab(photstrct *p, cpl_table *intab, casu_fits *im,
71 int minstars, cpl_image *schl_n, cpl_image *schl_s);
72static void getextinct(cpl_image *schl_n, cpl_image *schl_s, double ra,
73 double dec, float *ebv);
74static void radectolb(double ra, double dec, float epoch, double *gal_l,
75 double *gal_b);
76static void photdistort(casu_fits *im, cpl_table *outtab);
77static void getproj_pixsize(cpl_wcs *wcs, double crv1, double tand,
78 double secd, double x, double y, double *pixsize);
79
80static float propertylist_get_float_or_default(const cpl_propertylist * list,
81 const char * name, const float default_val);
82
85/* NB: This routine should be used only for a pawprint or a tile. Not for
86 a whole night. */
87
88/*---------------------------------------------------------------------------*/
196/*---------------------------------------------------------------------------*/
197
198extern int casu_photcal_extinct(casu_fits **images, casu_tfits **mstds,
199 casu_tfits **cats, int nimages,
200 char *filt, cpl_table *phottab, int minstars,
201 cpl_frame *schlf_n, cpl_frame *schlf_s,
202 const char *expkey, const char *amkey,
203 float magerrcut, int *status) {
204 float **stdmagptr,*resall3,*resall5,apcor3,apcor5,exptime,**magerrptr;
205 float airmass,*catcore3,*catcore5,*resim3,*resim5,cf,fluxmag3,fluxmag5;
206 float refmag,extinct,dm3,dm5,med3,mad,med5,sig3,sig5;
207 float rcore,lim5,dx,skylev,skbrt,*ebmvall,*zps3,*zps5,medebv,med;
208 float sig3det,sig5det,*ebmv,blankvalue=-99.0,sumskbr;
209 float sknoise,sumsat;
210 int nresall,nalloc_resall,i,j,k,ncat,nresim,nresimtot;
211 int ngood,oops,nlim,isrubbish,*dodgy,crud;
212 const char *fctid = "casu_photcal_extinct";
213 casu_fits *im;
214 cpl_propertylist *ehu_im,*ehu_cat,*phu_im,*phu_cat;
215 cpl_table *stds;
216 cpl_image *schl_n,*schl_s;
217 photstrct p;
218
219 /* Inherited status */
220
221 if (*status != CASU_OK)
222 return(*status);
223
224 /* Check for nonsense errors */
225
226 if (nimages <= 0) {
227 cpl_msg_error(fctid,"No images included in photometric calibration");
228 FATAL_ERROR
229 }
230
231 /* Get the Schlegel maps */
232
233 if (schlf_n == NULL || schlf_s == NULL) {
234 schl_n = NULL;
235 schl_s = NULL;
236 } else {
237 schl_n = cpl_image_load(cpl_frame_get_filename(schlf_n),CPL_TYPE_FLOAT,
238 0,0);
239 schl_s = cpl_image_load(cpl_frame_get_filename(schlf_s),CPL_TYPE_FLOAT,
240 0,0);
241 if (cpl_error_get_code() != CPL_ERROR_NONE) {
242 cpl_msg_error(fctid,"Unable to read Schlegel maps");
243 freeimage(schl_n);
244 freeimage(schl_s);
245 FATAL_ERROR
246 }
247 }
248
249 /* Set up the structure that will give us the colour equations for
250 this filter later on */
251
252 if (casu_phot_open(phottab,filt,&p) != CASU_OK)
253 FATAL_ERROR
254
255 /* Get a workspace to hold the pointers to the magnitude columns */
256
257 stdmagptr = cpl_malloc(p.ncolumns_coleq*sizeof(float *));
258 if (p.coleq_errcols != NULL)
259 magerrptr = cpl_malloc(p.ncolumns_coleq*sizeof(float *));
260 else
261 magerrptr = NULL;
262
263 /* Get some workspace to hold all the zeropoints for all the images
264 in the input list. This is an initial allocation and more can be
265 made available later if needed */
266
267 resall3 = cpl_malloc(INITALLOC*sizeof(float));
268 resall5 = cpl_malloc(INITALLOC*sizeof(float));
269 ebmvall = cpl_malloc(INITALLOC*sizeof(float));
270 nresall = 0;
271 nalloc_resall = INITALLOC;
272 zps3 = cpl_malloc(nimages*sizeof(float));
273 zps5 = cpl_malloc(nimages*sizeof(float));
274 ngood = 0;
275 nresimtot = 0;
276 dodgy = cpl_calloc(nimages,sizeof(int));
277
278 /* Loop for the input images and catalogues. Create some shorthand
279 variables. */
280
281 nlim = 0;
282 float sumlim = 0.0;
283 sumsat = 0.0;
284 sumskbr = 0.0;
285 for (i = 0; i < nimages; i++) {
286 im = images[i];
287 phu_im = casu_fits_get_phu(im);
288 ehu_im = casu_fits_get_ehu(im);
289 stds = casu_tfits_get_table(mstds[i]);
290 ehu_cat = casu_tfits_get_ehu(cats[i]);
291
292 /* Is this image any good? */
293
294 if (casu_fits_get_status(im) != CASU_OK) {
295 cpl_msg_warning(fctid,"Dummy image %s",casu_fits_get_fullname(im));
296 write_hdr_1(ehu_im,0,0.0,1.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,1);
297 write_hdr_1(ehu_cat,0,0.0,1.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,0);
298 dodgy[i] = 1;
299 continue;
300 }
301
302 /* Are there any stars? */
303
304 ncat = (int)cpl_table_get_nrow(stds);
305 if (mstds[i] == NULL || ncat < minstars) {
306 cpl_msg_warning(fctid,
307 "Too few standards available in %" CPL_SIZE_FORMAT,
308 (cpl_size)(i+1));
309 cpl_error_reset();
310 write_hdr_1(ehu_im,ncat,0.0,1.0,0.0,0.0,1.0,0.0,p.atm_extcoef,0.0,0.0,1);
311 write_hdr_1(ehu_cat,ncat,0.0,1.0,0.0,0.0,1.0,0.0,p.atm_extcoef,0.0,0.0,0);
312 dodgy[i] = 1;
313 continue;
314 }
315
316 /* Now for the input catalogues. Start by getting some useful info
317 from the header */
318
319 apcor3 = cpl_propertylist_get_float(ehu_cat,"APCOR3");
320 apcor5 = cpl_propertylist_get_float(ehu_cat,"APCOR5");
321 rcore = cpl_propertylist_get_float(ehu_cat,"ESO DRS RCORE");
322 skylev = cpl_propertylist_get_float(ehu_cat,"ESO DRS SKYLEVEL");
323 sknoise = cpl_propertylist_get_float(ehu_cat,"ESO DRS SKYNOISE");
324 dx = pixsize(ehu_im);
325 exptime = (float)cpl_propertylist_get_double(phu_im,expkey);
326 airmass = (float)cpl_propertylist_get_double(phu_im,amkey);
327 if (cpl_error_get_code() != CPL_ERROR_NONE) {
328 cpl_msg_error(fctid,"Unable to get header %s or %s info",expkey,
329 amkey);
330 cpl_error_reset();
331 continue;
332 }
333
334 /* Add some extra info to the table */
335
336 modifytab(&p,stds,im,minstars,schl_n,schl_s);
337
338 /* Dereference some of the columns */
339
340 ncat = (int)cpl_table_get_nrow(stds);
341 catcore3 = cpl_table_get_data_float(stds,"Aper_flux_3");
342 catcore5 = cpl_table_get_data_float(stds,"Aper_flux_5");
343 ebmv = cpl_table_get_data_float(stds,"ebmv");
344 for (j = 0; j < p.ncolumns_coleq; j++) {
345 cpl_table_fill_invalid_float(stds,(p.coleq_columns)[j],blankvalue);
346 stdmagptr[j] = cpl_table_get_data_float(stds,(p.coleq_columns)[j]);
347 if (stdmagptr[j] == NULL)
348 {
349 cpl_msg_error(fctid,"Unable to find filter column %s in photometric calibration table", p.coleq_columns[j]);
350 FATAL_ERROR
351 }
352
353 if (magerrptr != NULL) {
354 cpl_table_fill_invalid_float(stds,(p.coleq_errcols)[j],blankvalue);
355 magerrptr[j] = cpl_table_get_data_float(stds,(p.coleq_errcols)[j]);
356 }
357 }
358
359 /* Get some workspace for the results arrays for this image */
360
361 resim3 = cpl_malloc(ncat*sizeof(float));
362 resim5 = cpl_malloc(ncat*sizeof(float));
363 nresim = 0;
364
365 /* Loop for all the standards */
366
367 extinct = p.atm_extcoef*(airmass - 1.0);
368 for (j = 0; j < ncat; j++) {
369
370 /* Do core magnitude calculation */
371
372 cf = catcore3[j]/exptime;
373 if (cf < 1.0)
374 cf = 1.0;
375 fluxmag3 = 2.5*log10((double)cf) + apcor3;
376 cpl_table_set_float(stds,"instmag3",j,fluxmag3);
377 cf = catcore5[j]/exptime;
378 if (cf < 1.0)
379 cf = 1.0;
380 fluxmag5 = 2.5*log10((double)cf) + apcor5;
381 cpl_table_set_float(stds,"instmag5",j,fluxmag5);
382
383 /* Work out a reference magnitude. Cut out stars where the
384 magnitude error is too high */
385
386 refmag = p.mag_offset;
387 oops = 0;
388 for (k = 0; k < p.ncolumns_coleq; k++) {
389 if (stdmagptr[k][j] == blankvalue) {
390 oops = 1;
391 break;
392 } else if (magerrptr != NULL) {
393 if (magerrptr[k][j] > magerrcut) {
394 oops = 1;
395 break;
396 }
397 }
398 refmag += ((p.coleq_coefs)[k]*stdmagptr[k][j]);
399 }
400 if (oops)
401 continue;
402 cpl_table_set_float(stds,"refmag",j,refmag);
403
404 /* Work out zero points and store them away for later */
405
406 dm3 = refmag + fluxmag3 + extinct;
407 dm5 = refmag + fluxmag5 + extinct;
408 cpl_table_set_float(stds,"dm3",j,dm3);
409 cpl_table_set_float(stds,"dm5",j,dm5);
410 resim3[nresim] = dm3;
411 resim5[nresim++] = dm5;
412 ebmvall[nresall] = ebmv[j];
413 resall3[nresall] = dm3;
414 resall5[nresall++] = dm5;
415 if (nresall == nalloc_resall) {
416 nalloc_resall += INITALLOC;
417 resall3 = cpl_realloc(resall3,nalloc_resall*sizeof(float));
418 resall5 = cpl_realloc(resall5,nalloc_resall*sizeof(float));
419 ebmvall = cpl_realloc(ebmvall,nalloc_resall*sizeof(float));
420 }
421 }
422
423 /* Ok, what is the mean zeropoint for this image? */
424
425 if (nresim > 0) {
426 (void)casu_medmad(resim3,NULL,(long)nresim,&med3,&mad);
427 sig3 = mad*1.48;
428 (void)casu_medmad(resim5,NULL,(long)nresim,&med5,&mad);
429 sig5 = mad*1.48;
430 zps3[ngood] = med3;
431 zps5[ngood++] = med5;
432 crud = 0;
433 } else {
434 med3 = 0.0;
435 med5 = 0.0;
436 sig3 = 1.0;
437 sig5 = 1.0;
438 crud = 1;
439 }
440
441 /* How many stars were cut from the original file? */
442
443 nresimtot += cpl_table_get_nrow(stds);
444
445 /* Delete some workspace */
446
447 freespace(resim3);
448 freespace(resim5);
449
450 /* Calculate the limiting magnitudes */
451 float lim3 = 0;
452 if (! crud) {
453 lim3 = casu_calculate_abmag_lim(med3 + 2.5 * log10(exptime) - extinct,
454 sknoise, rcore, exptime, apcor3, extinct);
455 lim5 = med5 - 2.5*log10((5.0*sknoise*2.0*rcore*sqrt(CPL_MATH_PI))/exptime) -
456 apcor5 - extinct;
457 } else {
458 med3 = p.default_zp;
459 med5 = p.default_zp;
460 lim3 = casu_calculate_abmag_lim(med3 + 2.5 * log10(exptime) - extinct,
461 sknoise, rcore, exptime, apcor3, extinct);
462 lim5 = med5 - 2.5*log10((5.0*sknoise*2.0*rcore*sqrt(CPL_MATH_PI))/exptime) -
463 apcor5 - extinct;
464 }
465
466 /* Calculate sky brightness */
467
468 skbrt = med3 - 2.5*log10(skylev/(exptime*dx*dx)) - extinct;
469
470 /* Calculate the saturation magnitude */
471 const float psf_fwhm = propertylist_get_float_or_default(ehu_cat,"PSF_FWHM", 1.0f);
472 const float mean_sky = propertylist_get_float_or_default(ehu_cat,"ESO QC MEAN_SKY", 1.0f);
473 /*Using image header because HAWKI does not have pixelscale in catalog*/
474 const float pixel_scale = propertylist_get_float_or_default(ehu_im,"ESO QC WCS_SCALE", 1.0f);
475
476 const float satmag = casu_calculate_abmag_sat(med3 + 2.5 * log10(exptime) - extinct,
477 65e3f, mean_sky, psf_fwhm, pixel_scale, exptime);
478
479 if (!crud) {
480 sumlim += lim3;
481 sumsat += satmag;
482 sumskbr += skbrt;
483 nlim++;
484 }
485
486 /* Write out header stuff. First for the image and then for the
487 catalogue. NB: QC is not allowed to appear in the catalogue */
488
489 write_hdr_1(ehu_im,nresim,med3,sig3,lim3,med5,sig5,lim5,p.atm_extcoef,
490 extinct,skbrt,0);
491 write_hdr_1(ehu_cat,nresim,med3,sig3,lim3,med5,sig5,lim5,p.atm_extcoef,
492 extinct,skbrt,0);
493 cpl_propertylist_update_double(ehu_im,"ABMAGSAT",satmag);
494 cpl_propertylist_set_comment(ehu_im,"ABMAGSAT",
495 "Saturation limit for point sources");
496 cpl_propertylist_update_double(ehu_cat,"ABMAGSAT",satmag);
497 cpl_propertylist_set_comment(ehu_cat,"ABMAGSAT",
498 "Saturation limit for point sources");
499 }
500
501 /* Ok, what is the mean zeropoint for all images? */
502
503 if (nresall > 0) {
504 (void)casu_medmad(resall3,NULL,(long)nresall,&med3,&mad);
505 sig3 = mad*1.48;
506 (void)casu_medmad(resall5,NULL,(long)nresall,&med5,&mad);
507 sig5 = mad*1.48;
508 (void)casu_medmad(ebmvall,NULL,(long)nresall,&medebv,&mad);
509 isrubbish = 0;
510 } else {
511 med3 = p.default_zp;
512 sig3 = p.default_zp_err;
513 med5 = 0.0;
514 sig5 = 1.0;
515 medebv = -1.0;
516 isrubbish = 1;
517 }
518 char const * const fluxcal = isrubbish ? "UNCALIBRATED" : "ABSOLUTE";
519
520 /* If there were good images, then calculate the RMS of the detector
521 level zeropoints in both apertures */
522
523 if (ngood > 1) {
524 (void)casu_medmad(zps3,NULL,(long)ngood,&med,&mad);
525 sig3det = mad*1.48;
526 (void)casu_medmad(zps5,NULL,(long)ngood,&med,&mad);
527 sig5det = mad*1.48;
528 } else {
529 sig3det = sig3;
530 sig5det = sig5;
531 }
532 if (nlim > 0) {
533 sumlim /= (float)nlim;
534 sumskbr /= (float)nlim;
535 sumsat /= (float)nlim;
536 }
537
538 /* Delete some workspace */
539
540 freespace(resall3);
541 freespace(resall5);
542 freespace(ebmvall);
543 freespace(stdmagptr);
544 freespace(magerrptr);
545 freespace(zps3);
546 freespace(zps5);
547 freeimage(schl_n);
548 freeimage(schl_s);
549 casu_phot_close(&p);
550
551 /* Write these results to the header of the images and the catalogues.
552 First the images */
553
554 for (i = 0; i < nimages; i++) {
555 im = images[i];
556 ehu_im = casu_fits_get_ehu(im);
557 ehu_cat = casu_tfits_get_ehu(cats[i]);
558 phu_im = casu_fits_get_phu(im);
559 phu_cat = casu_tfits_get_phu(cats[i]);
560
561 cpl_propertylist_update_string(phu_im,"FLUXCAL",fluxcal);
562 cpl_propertylist_set_comment(phu_im,"FLUXCAL",
563 "Certifies the validity of PHOTZP");
564 cpl_propertylist_update_string(phu_cat,"FLUXCAL",fluxcal);
565 cpl_propertylist_set_comment(phu_cat,"FLUXCAL",
566 "Certifies the validity of PHOTZP");
567
568 /*According to the PHASE 3 standard PHOTZP has to absorb the exposure
569 * time and the extinciton*/
570 exptime = 1.0; /* Assumption in case of missing keywords */
571 extinct = 0.0; /* Assumption in case of missing keywords */
572 exptime = (float)cpl_propertylist_get_double(phu_im,expkey);
573 extinct = cpl_propertylist_get_float(ehu_im,"ESO DRS EXTINCT");
574 double photzp = 0.0;
575 if(med3 != 0.0)
576 photzp = med3 + 2.5*log10(exptime) - extinct;
577
578 cpl_propertylist_update_int(ehu_im,"ESO DRS MAGNZPTALL",nresall);
579 cpl_propertylist_set_comment(ehu_im,"ESO DRS MAGNZPTALL",
580 "number of stars in all magzpt calc");
581 cpl_propertylist_update_double(ehu_im,"ESO DRS ZPALL1",med3);
582 cpl_propertylist_set_comment(ehu_im,"ESO DRS ZPALL1",
583 "[mag] zeropoint 1*rcore all images");
584 cpl_propertylist_update_double(ehu_im,"ESO DRS ZPSIGALL1",sig3);
585 cpl_propertylist_set_comment(ehu_im,"ESO DRS ZPSIGALL1",
586 "[mag] zeropoint sigma 1*rcore all images");
587 cpl_propertylist_update_double(ehu_im,"ESO DRS ZPALL2",med5);
588 cpl_propertylist_set_comment(ehu_im,"ESO DRS ZPALL2",
589 "[mag] zeropoint 2*rcore all images");
590 cpl_propertylist_update_double(ehu_im,"ESO DRS ZPSIGALL2",sig5);
591 cpl_propertylist_set_comment(ehu_im,"ESO DRS ZPSIGALL2",
592 "[mag] zeropoint sigma 2*rcore all images");
593 cpl_propertylist_update_double(ehu_im,"ESO DRS MEDEBV",medebv);
594 cpl_propertylist_set_comment(ehu_im,"ESO DRS MEDEBV",
595 "[mag] median galactic colour excess");
596 cpl_propertylist_update_double(ehu_im,"ESO DRS SIGDET1",sig3det);
597 cpl_propertylist_set_comment(ehu_im,"ESO DRS SIGDET1",
598 "[mag] sigma det-level zpt 1*rcore");
599 cpl_propertylist_update_double(ehu_im,"ESO DRS SIGDET2",sig5det);
600 cpl_propertylist_set_comment(ehu_im,"ESO DRS SIGDET2",
601 "[mag] sigma det-level zpt 2*rcore");
602 cpl_propertylist_update_double(ehu_im,"ESO QC MAGZPT",med3);
603 cpl_propertylist_set_comment(ehu_im,"ESO QC MAGZPT",
604 "[mag] photometric zeropoint");
605 cpl_propertylist_update_double(ehu_im,"ESO QC MAGZERR",sig3det);
606 cpl_propertylist_set_comment(ehu_im,"ESO QC MAGZERR",
607 "[mag] photometric zeropoint error");
608 cpl_propertylist_update_double(ehu_im,"ESO QC SKYBRIGHT",sumskbr);
609 cpl_propertylist_set_comment(ehu_im,"ESO QC SKYBRIGHT",
610 "[mag/arcsec**2] sky brightness");
611 cpl_propertylist_update_double(ehu_im,"PHOTZP",photzp);
612 cpl_propertylist_set_comment(ehu_im,"PHOTZP",
613 "[mag] photometric zeropoint");
614 cpl_propertylist_update_double(ehu_im,"PHOTZPER",sig3det);
615 cpl_propertylist_set_comment(ehu_im,"PHOTZPER",
616 "[mag] uncertainty on PHOTZP");
617 cpl_propertylist_update_int(ehu_im,"ESO QC MAGNZPT",nresimtot);
618 cpl_propertylist_set_comment(ehu_im,"ESO QC MAGNZPT",
619 "number of stars in magzpt calc");
620 cpl_propertylist_update_bool(ehu_im,"ZPFUDGED",isrubbish);
621 cpl_propertylist_set_comment(ehu_im,"ZPFUDGED",
622 "TRUE if the ZP not derived from stds");
623 if (dodgy[i]) {
624 cpl_propertylist_update_double(ehu_im,"ABMAGSAT",sumsat);
625 cpl_propertylist_set_comment(ehu_im,"ABMAGSAT",
626 "Saturation limit for point sources");
627 cpl_propertylist_update_double(ehu_im,"ABMAGLIM",sumlim);
628 cpl_propertylist_set_comment(ehu_im,"ABMAGLIM",
629 "[mag] 5 sigma limiting mag");
630 cpl_propertylist_update_double(ehu_im,"ESO QC LIMITING_MAG",sumlim);
631 cpl_propertylist_set_comment(ehu_im,"ESO QC LIMITING_MAG",
632 "[mag] 5 sigma limiting mag.");
633 }
634
635 /* Now the catalogues */
636
637 cpl_propertylist_update_int(ehu_cat,"ESO DRS MAGNZPTALL",nresall);
638 cpl_propertylist_set_comment(ehu_cat,"ESO DRS MAGNZPTALL",
639 "number of stars in all magzpt calc");
640 cpl_propertylist_update_double(ehu_cat,"ESO DRS ZPALL1",med3);
641 cpl_propertylist_set_comment(ehu_cat,"ESO DRS ZPALL1",
642 "[mag] zeropoint 1*rcore all group images");
643 cpl_propertylist_update_double(ehu_cat,"ESO DRS ZPSIGALL1",sig3);
644 cpl_propertylist_set_comment(ehu_cat,"ESO DRS ZPSIGALL1",
645 "[mag] zeropoint sigma 1*rcore all group images");
646 cpl_propertylist_update_double(ehu_cat,"ESO DRS ZPALL2",med5);
647 cpl_propertylist_set_comment(ehu_cat,"ESO DRS ZPALL2",
648 "[mag] zeropoint 2*rcore all group images");
649 cpl_propertylist_update_double(ehu_cat,"ESO DRS ZPSIGALL2",sig5);
650 cpl_propertylist_set_comment(ehu_cat,"ESO DRS ZPSIGALL2",
651 "[mag] zeropoint sigma 2*rcore all group images");
652 cpl_propertylist_update_double(ehu_cat,"ESO DRS MEDEBV",medebv);
653 cpl_propertylist_set_comment(ehu_cat,"ESO DRS MEDEBV",
654 "[mag] median galactic colour excess");
655 cpl_propertylist_update_double(ehu_cat,"ESO DRS SIGDET1",sig3det);
656 cpl_propertylist_set_comment(ehu_cat,"ESO DRS SIGDET1",
657 "[mag] sigma det-level zpt 1*rcore");
658 cpl_propertylist_update_double(ehu_cat,"ESO DRS SIGDET2",sig5det);
659 cpl_propertylist_set_comment(ehu_cat,"ESO DRS SIGDET2",
660 "[mag] sigma det-level zpt 2*rcore");
661 cpl_propertylist_update_double(ehu_cat,"ESO QC MAGZPT",med3);
662 cpl_propertylist_set_comment(ehu_cat,"ESO QC MAGZPT",
663 "[mag] photometric zeropoint");
664 cpl_propertylist_update_double(ehu_cat,"ESO QC MAGZERR",sig3det);
665 cpl_propertylist_set_comment(ehu_cat,"ESO QC MAGZERR",
666 "[mag] photometric zeropoint error");
667 cpl_propertylist_update_double(ehu_cat,"ESO QC SKYBRIGHT",sumskbr);
668 cpl_propertylist_set_comment(ehu_cat,"ESO QC SKYBRIGHT",
669 "[mag/arcsec**2] sky brightness");
670 cpl_propertylist_update_double(ehu_cat,"PHOTZP",photzp);
671 cpl_propertylist_set_comment(ehu_cat,"PHOTZP",
672 "[mag] photometric zeropoint");
673 cpl_propertylist_update_double(ehu_cat,"PHOTZPER",sig3det);
674 cpl_propertylist_set_comment(ehu_cat,"PHOTZPER",
675 "[mag] uncertainty on PHOTZP");
676 cpl_propertylist_update_int(ehu_cat,"ESO QC MAGNZPT",nresimtot);
677 cpl_propertylist_set_comment(ehu_cat,"ESO QC MAGNZPT",
678 "number of stars in magzpt calc");
679 cpl_propertylist_update_bool(ehu_cat,"ZPFUDGED",isrubbish);
680 cpl_propertylist_set_comment(ehu_cat,"ZPFUDGED",
681 "TRUE if the ZP not derived from stds");
682 if (dodgy[i]) {
683 cpl_propertylist_update_double(ehu_cat,"ABMAGSAT",sumsat);
684 cpl_propertylist_set_comment(ehu_cat,"ABMAGSAT",
685 "Saturation limit for point sources");
686 cpl_propertylist_update_double(ehu_cat,"ABMAGLIM",sumlim);
687 cpl_propertylist_set_comment(ehu_cat,"ABMAGLIM",
688 "[mag] 5 sigma limiting mag");
689 cpl_propertylist_update_double(ehu_cat,"ESO QC LIMITING_MAG",sumlim);
690 cpl_propertylist_set_comment(ehu_cat,"ESO QC LIMITING_MAG",
691 "[mag] 5 sigma limiting mag.");
692 }
693
694 /* Update the matched standards headers */
695
696 if (mstds[i] != NULL) {
697 phu_cat = casu_tfits_get_phu(mstds[i]);
698 cpl_propertylist_update_string(phu_cat,"FLUXCAL",fluxcal);
699 cpl_propertylist_set_comment(phu_cat,"FLUXCAL",
700 "Certifies the validity of PHOTZP");
701
702 ehu_cat = casu_tfits_get_ehu(mstds[i]);
703 cpl_propertylist_update_int(ehu_cat,"ESO DRS MAGNZPTALL",nresall);
704 cpl_propertylist_set_comment(ehu_cat,"ESO DRS MAGNZPTALL",
705 "number of stars in all magzpt calc");
706 cpl_propertylist_update_double(ehu_cat,"ESO DRS ZPALL1",med3);
707 cpl_propertylist_set_comment(ehu_cat,"ESO DRS ZPALL1",
708 "[mag] zeropoint 1*rcore all group images");
709 cpl_propertylist_update_double(ehu_cat,"ESO DRS ZPSIGALL1",sig3);
710 cpl_propertylist_set_comment(ehu_cat,"ESO DRS ZPSIGALL1",
711 "[mag] zeropoint sigma 1*rcore all group images");
712 cpl_propertylist_update_double(ehu_cat,"ESO DRS ZPALL2",med5);
713 cpl_propertylist_set_comment(ehu_cat,"ESO DRS ZPALL2",
714 "[mag] zeropoint 2*rcore all group images");
715 cpl_propertylist_update_double(ehu_cat,"ESO DRS ZPSIGALL2",sig5);
716 cpl_propertylist_set_comment(ehu_cat,"ESO DRS ZPSIGALL2",
717 "[mag] zeropoint sigma 2*rcore all group images");
718 cpl_propertylist_update_double(ehu_cat,"ESO DRS MEDEBV",medebv);
719 cpl_propertylist_set_comment(ehu_cat,"ESO DRS MEDEBV",
720 "[mag] median galactic colour excess");
721 cpl_propertylist_update_double(ehu_cat,"ESO DRS SIGDET1",sig3det);
722 cpl_propertylist_set_comment(ehu_cat,"ESO DRS SIGDET1",
723 "[mag] sigma det-level zpt 1*rcore");
724 cpl_propertylist_update_double(ehu_cat,"ESO DRS SIGDET2",sig5det);
725 cpl_propertylist_set_comment(ehu_cat,"ESO DRS SIGDET2",
726 "[mag] sigma det-level zpt 2*rcore");
727 cpl_propertylist_update_double(ehu_cat,"ESO QC MAGZPT",med3);
728 cpl_propertylist_set_comment(ehu_cat,"ESO QC MAGZPT",
729 "[mag] photometric zeropoint");
730 cpl_propertylist_update_double(ehu_cat,"ESO QC MAGZERR",sig3det);
731 cpl_propertylist_set_comment(ehu_cat,"ESO QC MAGZERR",
732 "[mag] photometric zeropoint error");
733 cpl_propertylist_update_double(ehu_cat,"ESO QC SKYBRIGHT",sumskbr);
734 cpl_propertylist_set_comment(ehu_cat,"ESO QC SKYBRIGHT",
735 "[mag/arcsec**2] sky brightness");
736 cpl_propertylist_update_double(ehu_cat,"PHOTZP",photzp);
737 cpl_propertylist_set_comment(ehu_cat,"PHOTZP",
738 "[mag] photometric zeropoint");
739 cpl_propertylist_update_double(ehu_cat,"PHOTZPER",sig3det);
740 cpl_propertylist_set_comment(ehu_cat,"PHOTZPER",
741 "[mag] uncertainty on PHOTZP");
742 cpl_propertylist_update_int(ehu_cat,"ESO QC MAGNZPT",nresimtot);
743 cpl_propertylist_set_comment(ehu_cat,"ESO QC MAGNZPT",
744 "number of stars in magzpt calc");
745 cpl_propertylist_update_bool(ehu_cat,"ZPFUDGED",isrubbish);
746 cpl_propertylist_set_comment(ehu_cat,"ZPFUDGED",
747 "TRUE if the ZP not derived from stds");
748 }
749 }
750 freespace(dodgy);
751
752 /* Get out of here */
753
754 GOOD_STATUS
755
756}
757
758/*---------------------------------------------------------------------------*/
785/*---------------------------------------------------------------------------*/
786extern int casu_remove_mag_outside_range(casu_tfits **mstds, const int nimages,
787 char *filt, cpl_table *phottab,
788 const float low_mag, const float high_mag)
789{
790
791 photstrct p;
792
793 if (casu_phot_open(phottab,filt,&p) != CASU_OK)
794 return -1;
795
796 int i, j;
797 int num_erased = 0;
798 for (i = 0; i < nimages; i++) {
799 casu_tfits * ctfits = mstds[i];
800 cpl_table * stds = casu_tfits_get_table(ctfits);
801 cpl_table_unselect_all(stds);
802 for (j = 0; j < p.ncolumns_coleq; j++) {
803 const char * clnm_name = (p.coleq_columns)[j];
804 if(!cpl_table_has_column(stds, clnm_name))
805 {
806 casu_phot_close(&p);
807 return -1;
808 }
809 cpl_table_or_selected_float(stds, clnm_name, CPL_LESS_THAN, low_mag);
810 cpl_table_or_selected_float(stds, clnm_name, CPL_GREATER_THAN, high_mag);
811 }
812 num_erased += cpl_table_count_selected(stds);
813 cpl_table_erase_selected(stds);
814 cpl_table_select_all(stds);
815 }
816
817 casu_phot_close(&p);
818 return num_erased;
819}
820
821
822/*---------------------------------------------------------------------------*/
839/*---------------------------------------------------------------------------*/
840
841static double pixsize (cpl_propertylist *plist) {
842 cpl_wcs *wcs;
843 double *cd,pix;
844
845 wcs = cpl_wcs_new_from_propertylist(plist);
846 cd = cpl_matrix_get_data((cpl_matrix *)cpl_wcs_get_cd(wcs));
847 pix = 3600.0*sqrt(fabs(cd[0]*cd[3] - cd[1]*cd[2]));
848 cpl_wcs_delete(wcs);
849 return(pix);
850}
851
852/*---------------------------------------------------------------------------*/
877/*---------------------------------------------------------------------------*/
878
879static int casu_phot_open(cpl_table *phottab, char *filt, photstrct *p) {
880 const char *fctid = "casu_phot_open";
881 int ns,nerr,null,nr;
882 cpl_table *subset;
883 char **filts;
884 const char *req_cols[9] = {"filter_name","atm_extcoef","mag_offset",
885 "coleq_columns","coleq_errcols","coleq_coefs",
886 "gal_extcoef","default_zp","default_zp_err"};
887
888 /* Initialise a few things */
889
890 p->coleq_coefs = NULL;
891 p->coleq_columns = NULL;
892 p->coleq_errcols = NULL;
893 p->ncolumns_coleq = 0;
894 p->mag_offset = 0.0;
895
896 /* Check the table and make sure it has all the required columns */
897
898 nerr = 0;
899 for (ns = 0; ns < 9; ns++) {
900 if (! cpl_table_has_column(phottab,req_cols[ns])) {
901 cpl_msg_error(fctid,"Photometry table missing column %s",
902 req_cols[ns]);
903 nerr++;
904 }
905 }
906 if (nerr > 0)
907 return(CASU_FATAL);
908
909 /* Search the table and find the rows that matches the filter. NB: we
910 can't use cpl_table_and_selected_string because it matches by regular
911 expression rather than exact matching! So just loop through and choose
912 the first one that matches exactly. There shouldn't be more than one! */
913
914 filts = cpl_table_get_data_string(phottab,"filter_name");
915 nr = cpl_table_get_nrow(phottab);
916 nerr = 1;
917 for (ns = 0; ns < nr; ns++) {
918 if (strncmp(filts[ns],filt,16) == 0) {
919 nerr = 0;
920 break;
921 }
922 }
923 if (nerr == 1) {
924 cpl_msg_error(fctid,"Unable to match photometry table to filter %s",
925 filt);
926 return(CASU_FATAL);
927 }
928 cpl_table_and_selected_window(phottab,ns,1);
929
930 /* Read the information from the selected row */
931
932 subset = cpl_table_extract_selected(phottab);
933 p->filter_name = (char *)cpl_table_get_string(subset,"filter_name",0);
934 p->atm_extcoef = cpl_table_get_float(subset,"atm_extcoef",0,&null);
935 p->mag_offset = cpl_table_get_float(subset,"mag_offset",0,&null);
936 p->gal_extcoef = cpl_table_get_float(subset,"gal_extcoef",0,&null);
937 p->default_zp = cpl_table_get_float(subset,"default_zp",0,&null);
938 p->default_zp_err = cpl_table_get_float(subset,"default_zp_err",0,&null);
939 if (extract_columns(subset,p) != CASU_OK) {
940 freetable(subset);
941 return(CASU_FATAL);
942 }
943 if (extract_coleq(subset,p) != CASU_OK) {
944 freetable(subset);
945 return(CASU_FATAL);
946 }
947 freetable(subset);
948
949 /* Get out of here */
950
951 return(CASU_OK);
952}
953
954/*---------------------------------------------------------------------------*/
970/*---------------------------------------------------------------------------*/
971
972static void casu_phot_close(photstrct *p) {
973 int j;
974
975 for (j = 0; j < p->ncolumns_coleq; j++) {
976 freespace((p->coleq_columns)[j]);
977 freespace((p->coleq_errcols)[j]);
978 }
979 freespace(p->coleq_columns);
980 freespace(p->coleq_errcols);
981 freespace(p->coleq_coefs);
982}
983
984/*---------------------------------------------------------------------------*/
1003/*---------------------------------------------------------------------------*/
1004
1005static int extract_columns(cpl_table *tab, photstrct *p) {
1006 int nv,i,j,k;
1007 char *v,*w,**z;
1008 const char *cols[2] = {"coleq_columns","coleq_errcols"};
1009
1010 /* Loop for the columns */
1011
1012 for (k = 0; k < 2; k++) {
1013
1014 /* Get the relevant value from the table */
1015
1016 v = cpl_strdup(cpl_table_get_string(tab,cols[k],0));
1017
1018 /* Count the number of commas in the string to see how many
1019 columns there are */
1020
1021 nv = 1;
1022 j = strlen(v);
1023 for (i = 0; i < j; i++)
1024 if (v[i] == ',')
1025 nv++;
1026 if (k == 0) {
1027 p->ncolumns_coleq = nv;
1028 } else {
1029 if (nv == 0 || nv != p->ncolumns_coleq) {
1030 p->coleq_errcols = NULL;
1031 freespace(v);
1032 return(CASU_OK);
1033 }
1034 }
1035
1036 /* Now parse the string into the column names */
1037
1038 z = cpl_malloc(nv*sizeof(char *));
1039 char *saveptr = NULL;
1040 for (i = 0; i < nv; i++) {
1041 if (i == 0)
1042 w = strtok_r(v,",",&saveptr);
1043 else
1044 w = strtok_r(NULL,",",&saveptr);
1045 z[i] = cpl_strdup(w);
1046 }
1047 if (k == 0)
1048 p->coleq_columns = z;
1049 else
1050 p->coleq_errcols = z;
1051 freespace(v);
1052 }
1053 return(CASU_OK);
1054}
1055
1056/*---------------------------------------------------------------------------*/
1075/*---------------------------------------------------------------------------*/
1076
1077static int extract_coleq(cpl_table *tab, photstrct *p) {
1078 int nv,i,j;
1079 char *v,*w;
1080 float *z;
1081
1082 /* Get the relevant value from the table */
1083
1084 v = cpl_strdup(cpl_table_get_string(tab,"coleq_coefs",0));
1085
1086 /* Count the number of commas in the string to see how many
1087 columns there are */
1088
1089 nv = 1;
1090 j = strlen(v);
1091 for (i = 0; i < j; i++)
1092 if (v[i] == ',')
1093 nv++;
1094
1095 /* Now parse the string into the colour equation values */
1096
1097 z = cpl_malloc(nv*sizeof(float));
1098 char *saveptr1 = NULL;
1099 for (i = 0; i < nv; i++) {
1100 if (i == 0)
1101 w = strtok_r(v,",", &saveptr1);
1102 else
1103 w = strtok_r(NULL,",", &saveptr1);
1104 z[i] = (float)atof(w);
1105 }
1106 p->coleq_coefs = z;
1107 freespace(v);
1108 return(CASU_OK);
1109}
1110
1111/*---------------------------------------------------------------------------*/
1150/*---------------------------------------------------------------------------*/
1151
1152static void write_hdr_1(cpl_propertylist *pl, int nresim, float med3,
1153 float sig3, float lim3, float med5, float sig5,
1154 float lim5, float extcoef, float extinct, float skybrt,
1155 int doqc) {
1156
1157 /* Write these results to the header of the image and the catalogue.
1158 First the QC headers for the image. These are not allowed to be
1159 copied into the catalogue headers...*/
1160
1161 if (doqc) {
1162 cpl_propertylist_update_double(pl,"ESO QC MAGZPT",med3);
1163 cpl_propertylist_set_comment(pl,"ESO QC MAGZPT",
1164 "[mag] photometric zeropoint");
1165 cpl_propertylist_update_double(pl,"ESO QC MAGZERR",sig3);
1166 cpl_propertylist_set_comment(pl,"ESO QC MAGZERR",
1167 "[mag] photometric zeropoint error");
1168 cpl_propertylist_update_int(pl,"ESO QC MAGNZPT",nresim);
1169 cpl_propertylist_set_comment(pl,"ESO QC MAGNZPT",
1170 "number of stars in magzpt calc");
1171 cpl_propertylist_update_double(pl,"ESO QC SKYBRIGHT",skybrt);
1172 cpl_propertylist_set_comment(pl,"ESO QC SKYBRIGHT",
1173 "[mag/arcsec**2] sky brightness");
1174 }
1175
1176 /* Now the DRS headers for the image */
1177
1178 cpl_propertylist_update_int(pl,"ESO DRS MAGNZPTIM",nresim);
1179 cpl_propertylist_set_comment(pl,"ESO DRS MAGNZPTIM",
1180 "number of stars in image magzpt calc");
1181
1182 cpl_propertylist_update_double(pl,"ESO DRS ZPIM1",med3);
1183 cpl_propertylist_set_comment(pl,"ESO DRS ZPIM1",
1184 "[mag] zeropoint 1*rcore this image only");
1185 cpl_propertylist_update_double(pl,"ESO DRS ZPSIGIM1",sig3);
1186 cpl_propertylist_set_comment(pl,"ESO DRS ZPSIGIM1",
1187 "[mag] zeropoint sigma 1*rcore this image only");
1188 cpl_propertylist_update_double(pl,"ESO DRS LIMIT_MAG1",lim3);
1189 cpl_propertylist_set_comment(pl,"ESO DRS LIMIT_MAG1",
1190 "[mag] 5 sigma limiting mag 1*rcore.");
1191 cpl_propertylist_update_double(pl,"ABMAGLIM",lim3);
1192 cpl_propertylist_set_comment(pl,"ABMAGLIM",
1193 "[mag] 5 sigma limiting mag");
1194 cpl_propertylist_update_double(pl,"ESO QC LIMITING_MAG",lim3);
1195 cpl_propertylist_set_comment(pl,"ESO QC LIMITING_MAG",
1196 "[mag] 5 sigma limiting mag.");
1197 cpl_propertylist_update_double(pl,"ESO DRS ZPIM2",med5);
1198 cpl_propertylist_set_comment(pl,"ESO DRS ZPIM2",
1199 "[mag] zeropoint 2*rcore this image only");
1200 cpl_propertylist_update_double(pl,"ESO DRS ZPSIGIM2",sig5);
1201 cpl_propertylist_set_comment(pl,"ESO DRS ZPSIGIM2",
1202 "[mag] zeropoint sigma 2*rcore this image only");
1203 cpl_propertylist_update_double(pl,"ESO DRS LIMIT_MAG2",lim5);
1204 cpl_propertylist_set_comment(pl,"ESO DRS LIMIT_MAG2",
1205 "[mag] 5 sigma limiting mag core5.");
1206 cpl_propertylist_update_double(pl,"ESO DRS EXTCOEF",extcoef);
1207 cpl_propertylist_set_comment(pl,"ESO DRS EXTCOEF",
1208 "[mag] Assumed extinction coefficient");
1209 cpl_propertylist_update_double(pl,"ESO DRS EXTINCT",extinct);
1210 cpl_propertylist_set_comment(pl,"ESO DRS EXTINCT",
1211 "[mag] Assumed extinction");
1212 cpl_propertylist_update_double(pl,"ESO DRS SKYBRIGHT",skybrt);
1213 cpl_propertylist_set_comment(pl,"ESO DRS SKYBRIGHT",
1214 "[mag/arcsec**2] sky brightness");
1215}
1216
1217/*---------------------------------------------------------------------------*/
1246/*---------------------------------------------------------------------------*/
1247
1248static void modifytab(photstrct *p, cpl_table *intab, casu_fits *im,
1249 int minstars, cpl_image *schl_n, cpl_image *schl_s) {
1250 float *ebmv,ebv,*galex;
1251 float *ra = NULL, *dec = NULL;
1252 double *rra = NULL, *ddec = NULL;
1253 int i,nrows;
1254 const char *fctid = "modifytab";
1255
1256 /* Count how many we've got. If there are too few left, then get out of
1257 here and signal an error */
1258
1259 nrows = (int)cpl_table_get_nrow(intab);
1260 if (nrows < minstars) {
1261 cpl_msg_error(fctid,"Matched standards has too few stars");
1262 return;
1263 }
1264
1265 /* Now create two more columns to include the estimated colour excess
1266 as E(B-V) from the Schlegel maps, and an estimate of the absorption
1267 in the relevant band for the observations */
1268
1269 if (! cpl_table_has_column(intab,"ebmv"))
1270 cpl_table_duplicate_column(intab,"ebmv",intab,"Peak_height");
1271 if (! cpl_table_has_column(intab,"galextinct"))
1272 cpl_table_duplicate_column(intab,"galextinct",intab,"Peak_height");
1273
1274 /* Add some columns for diagnostics now */
1275
1276 if (! cpl_table_has_column(intab,"instmag3")) {
1277 cpl_table_duplicate_column(intab,"instmag3",intab,"Peak_height");
1278 cpl_table_set_column_invalid(intab,"instmag3",0,nrows);
1279 }
1280 if (! cpl_table_has_column(intab,"instmag5")) {
1281 cpl_table_duplicate_column(intab,"instmag5",intab,"Peak_height");
1282 cpl_table_set_column_invalid(intab,"instmag5",0,nrows);
1283 }
1284 if (! cpl_table_has_column(intab,"refmag")) {
1285 cpl_table_duplicate_column(intab,"refmag",intab,"Peak_height");
1286 cpl_table_set_column_invalid(intab,"refmag",0,nrows);
1287 }
1288 if (! cpl_table_has_column(intab,"dm3")) {
1289 cpl_table_duplicate_column(intab,"dm3",intab,"Peak_height");
1290 cpl_table_set_column_invalid(intab,"dm3",0,nrows);
1291 }
1292 if (! cpl_table_has_column(intab,"dm5")) {
1293 cpl_table_duplicate_column(intab,"dm5",intab,"Peak_height");
1294 cpl_table_set_column_invalid(intab,"dm5",0,nrows);
1295 }
1296
1297 /* Get the data arrays for these new columns and use the Schlegel maps
1298 to work out values for them */
1299
1300 ebmv = cpl_table_get_data_float(intab,"ebmv");
1301 galex = cpl_table_get_data_float(intab,"galextinct");
1302 if (cpl_table_get_column_type(intab,"RA") == CPL_TYPE_FLOAT) {
1303 ra = cpl_table_get_data_float(intab,"RA");
1304 dec = cpl_table_get_data_float(intab,"Dec");
1305 } else {
1306 rra = cpl_table_get_data_double(intab,"RA");
1307 ddec = cpl_table_get_data_double(intab,"Dec");
1308 }
1309 for (i = 0; i < nrows; i++) {
1310 if (schl_n == NULL || schl_s == NULL) {
1311 ebv = 0.0;
1312 } else {
1313 if (cpl_table_get_column_type(intab,"RA") == CPL_TYPE_FLOAT && ra != NULL && dec != NULL) {
1314 getextinct(schl_n,schl_s,(double)(ra[i]),(double)(dec[i]),&ebv);
1315 } else if (cpl_table_get_column_type(intab,"RA") == CPL_TYPE_DOUBLE && rra != NULL && ddec != NULL){
1316 getextinct(schl_n,schl_s,rra[i],ddec[i],&ebv);
1317 } else {
1318 ebv = 0.0;
1319 }
1320 }
1321 ebmv[i] = ebv;
1322 galex[i] = p->gal_extcoef*ebv;
1323 }
1324
1325 /* Do the photometric distortion of the input fluxes */
1326
1327 photdistort(im,intab);
1328
1329 /* Get out of here */
1330
1331 return;
1332}
1333
1334/*---------------------------------------------------------------------------*/
1354/*---------------------------------------------------------------------------*/
1355
1356static void photdistort(casu_fits *im, cpl_table *outtab) {
1357 cpl_wcs *wcs;
1358 float *flux1,*flux2,*x,*y;
1359 int i,nrows,isnull;
1360 const cpl_array *crv;
1361 double crv1,tand,secd,distcor,ps1,ps2,psc;
1362
1363 /* Get the WCS descriptor and work out a few convenience variables */
1364
1365 wcs = cpl_wcs_new_from_propertylist(casu_fits_get_ehu(im));
1366 crv = cpl_wcs_get_crval(wcs);
1367 crv1 = DEGRAD*cpl_array_get(crv,0,&isnull);
1368 tand = tan(DEGRAD*cpl_array_get(crv,1,&isnull));
1369 secd = sqrt(1.0 + tand*tand);
1370
1371 /* Get the pixel size (sq arcsec) at the central position */
1372
1373 psc = pixsize(casu_fits_get_ehu(im));
1374 ps2 = psc*psc;
1375
1376 /* Dereference the table data */
1377
1378 flux1 = cpl_table_get_data_float(outtab,"Aper_flux_3");
1379 flux2 = cpl_table_get_data_float(outtab,"Aper_flux_5");
1380 x = cpl_table_get_data_float(outtab,"X_coordinate");
1381 y = cpl_table_get_data_float(outtab,"Y_coordinate");
1382 nrows = (int)cpl_table_get_nrow(outtab);
1383
1384 /* Now work out the distortion for each object */
1385
1386 for (i = 0; i < nrows; i++) {
1387 getproj_pixsize(wcs,crv1,tand,secd,(double)x[i],(double)y[i],&ps1);
1388 distcor = ps1/ps2;
1389 flux1[i] *= distcor;
1390 flux2[i] *= distcor;
1391 }
1392 freewcs(wcs);
1393}
1394
1395/*---------------------------------------------------------------------------*/
1416/*---------------------------------------------------------------------------*/
1417static float propertylist_get_float_or_default(const cpl_propertylist * list, const char * name,
1418 const float default_val){
1419
1420 cpl_boolean value_missing_or_mismatch = !cpl_propertylist_has(list, name);
1421 value_missing_or_mismatch = value_missing_or_mismatch || (cpl_propertylist_get_type(list, name) != CPL_TYPE_DOUBLE
1422 && cpl_propertylist_get_type(list, name) != CPL_TYPE_FLOAT);
1423 if(value_missing_or_mismatch) {
1424 cpl_msg_warning(cpl_func, "Unable to extract %s, fallback to %f", name, default_val);
1425 return default_val;
1426 }
1427
1428 return cpl_propertylist_get_float(list, name);
1429}
1430
1431/*---------------------------------------------------------------------------*/
1458/*---------------------------------------------------------------------------*/
1459
1460static void getproj_pixsize(cpl_wcs *wcs, double crv1, double tand,
1461 double secd, double x, double y, double *ps) {
1462 cpl_matrix *xy,*rd;
1463 cpl_array *stat;
1464 cpl_vector *xi,*eta;
1465 int i;
1466 double offx,offy,ra,dec,xiv,etav,bigd,dx,dy,*xira,*etara,dx1,dx2,dy1,dy2;
1467
1468 /* First, load up the corners of the input pixel */
1469
1470 xy = cpl_matrix_new(4,2);
1471 for (i = 0; i < 4; i++) {
1472 offx = (i < 2 ? -0.5 : 0.5);
1473 offy = ((i == 0 || i == 3) ? -0.5 : 0.5);
1474 cpl_matrix_set(xy,i,0,x+offx);
1475 cpl_matrix_set(xy,i,1,y+offy);
1476 }
1477
1478 /* Do the conversion to RA, Dec */
1479
1480 cpl_wcs_convert(wcs,xy,&rd,&stat,CPL_WCS_PHYS2WORLD);
1481 cpl_array_delete(stat);
1482 cpl_matrix_delete(xy);
1483
1484 /* Loop for each of the rows */
1485
1486 xi = cpl_vector_new(4);
1487 eta = cpl_vector_new(4);
1488 for (i = 0; i < 4; i++) {
1489 ra = cpl_matrix_get(rd,i,0);
1490 dec = cpl_matrix_get(rd,i,1);
1491 ra *= DEGRAD;
1492 dec *= DEGRAD;
1493 ra -= crv1;
1494 bigd = tan(dec)*tand + cos(ra);
1495 xiv = RADARCSEC*secd*sin(ra)/bigd;
1496 etav = RADARCSEC*(tan(dec) - tand*cos(ra))/bigd;
1497 cpl_vector_set(xi,i,xiv);
1498 cpl_vector_set(eta,i,etav);
1499 }
1500 cpl_matrix_delete(rd);
1501
1502 /* Now form the average size of the two sides and work out
1503 the pixel size */
1504
1505 xira = cpl_vector_get_data(xi);
1506 etara = cpl_vector_get_data(eta);
1507 dx1 = xira[1] - xira[0];
1508 dx2 = xira[3] - xira[2];
1509 dy1 = etara[1] - etara[0];
1510 dy2 = etara[3] - etara[2];
1511 dy = 0.5*(sqrt(dx1*dx1 + dy1*dy1) + sqrt(dx2*dx2 + dy2*dy2));
1512 dx1 = xira[1] - xira[2];
1513 dx2 = xira[0] - xira[3];
1514 dy1 = etara[1] - etara[2];
1515 dy2 = etara[0] - etara[3];
1516 dx = 0.5*(sqrt(dx1*dx1 + dy1*dy1) + sqrt(dx2*dx2 + dy2*dy2));
1517 *ps = dx*dy;
1518
1519 /* Tidy and exit */
1520
1521 cpl_vector_delete(xi);
1522 cpl_vector_delete(eta);
1523}
1524
1525/*---------------------------------------------------------------------------*/
1549/*---------------------------------------------------------------------------*/
1550
1551static void getextinct(cpl_image *schl_n, cpl_image *schl_s, double ra,
1552 double dec, float *ebv) {
1553 double gal_l,gal_b,sin_b,cos_l,sin_l;
1554 cpl_image *schl;
1555 float x,y,*schl_data,xx,yy,delx,dely;
1556 int ix,iy,iarg1,iarg2,iarg3,iarg4,nx,ny;
1557
1558 /* Get the galactic coordinates (radians) for this ra and dec */
1559
1560 radectolb(ra,dec,2000.0,&gal_l,&gal_b);
1561
1562 /* Get the relevant Schlegel data */
1563
1564 schl = (gal_b >= 0.0 ? schl_n : schl_s);
1565 schl_data = cpl_image_get_data_float(schl);
1566
1567 /* Get the x,y coordinates for this position. This formula is taken
1568 from the original Schlegel article */
1569
1570 sin_b = sin(gal_b);
1571 cos_l = cos(gal_l);
1572 sin_l = sin(gal_l);
1573 if (gal_b >= 0.0) {
1574 x = 2048.0*sqrt(1.0 - sin_b)*cos_l + 2047.5;
1575 y = -2048.0*sqrt(1.0 - sin_b)*sin_l + 2047.5;
1576 } else {
1577 x = 2048.0*sqrt(1.0 + sin_b)*cos_l + 2047.5;
1578 y = 2048.0*sqrt(1.0 + sin_b)*sin_l + 2047.5;
1579 }
1580
1581 /* Get the pixel and the ones next to it */
1582
1583 nx = (int)cpl_image_get_size_x(schl);
1584 ny = (int)cpl_image_get_size_y(schl);
1585 ix = min(nx-2,max(0,(int)x));
1586 iy = min(ny-2,max(0,(int)y));
1587 delx = x - (int)x;
1588 dely = y - (int)y;
1589 iarg1 = iy*nx + ix;
1590 iarg2 = iarg1 + 1;
1591 iarg3 = iarg1 + nx;
1592 iarg4 = iarg2 + nx;
1593
1594 /* Get the values and do the interpolation. */
1595
1596 xx = (1.0 - delx)*schl_data[iarg1] + delx*schl_data[iarg2];
1597 yy = (1.0 - delx)*schl_data[iarg3] + delx*schl_data[iarg4];
1598 *ebv = (1.0 - dely)*xx + dely*yy;
1599}
1600
1601/*---------------------------------------------------------------------------*/
1624/*---------------------------------------------------------------------------*/
1625
1626static void radectolb(double ra, double dec, float epoch, double *gal_l,
1627 double *gal_b) {
1628 double ti,tf,s,z,h,arcsecrad,ra2,dec2,cosdec1,sindec1,cosra1s,sinra1s;
1629 double cos_h,sin_h,x1,x2,sin_b,cosdec2,sindec2,costheta,sintheta;
1630 double cosdra,sindra,ra1,dec1,sinra2,cosra2;
1631 double a0=282.25,theta=62.6,gal_l0=33.0;
1632 float equin=1950;
1633
1634 /* Start by precessing coordinates to 1950 using IAU 1976 precession
1635 quuantities */
1636
1637 ti = (double)(epoch - 2000.0)/100.0;
1638 tf = (double)(equin - 2000.0)/100.0 - ti;
1639 s = (2306.2181 - 1.39656*ti - 0.000139*ti*ti)*tf +
1640 (0.30188 - 0.000344*ti)*tf*tf + 0.17998*tf*tf*tf;
1641 z = s + (0.79280 + 0.000410*ti)*tf*tf + 0.000205*tf*tf*tf;
1642 h = (2004.3109 - 0.85330*ti - 0.000217*ti*ti)*tf -
1643 (0.42665 + 0.000217*ti)*tf*tf - 0.041833*tf*tf*tf;
1644
1645 /* Convert to radians */
1646
1647 arcsecrad = 1.0/(CPL_MATH_DEG_RAD*3600.0);
1648 s *= arcsecrad;
1649 z *= arcsecrad;
1650 h *= arcsecrad;
1651 ra1 = ra/CPL_MATH_DEG_RAD;
1652 dec1 = dec/CPL_MATH_DEG_RAD;
1653
1654 /* Apply precession to give new RA and Dec in radians */
1655
1656 cosdec1 = cos(dec1);
1657 sindec1 = sin(dec1);
1658 cosra1s = cos(ra1+s);
1659 sinra1s = sin(ra1+s);
1660 cos_h = cos(h);
1661 sin_h = sin(h);
1662 dec2 = asin(cosdec1*cosra1s*sin_h + sindec1*cos_h);
1663 cosdec2 = cos(dec2);
1664 sinra2 = cosdec1*sinra1s/cosdec2;
1665 cosra2 = (cosdec1*cosra1s*cos_h - sindec1*sin_h)/cosdec2;
1666 ra2 = atan2(sinra2,cosra2) + z;
1667
1668 /* Check to make sure the new RA isn't negative */
1669
1670 if (ra2 < 0.0)
1671 ra2 += CPL_MATH_2PI;
1672
1673 /* Convert galactic reference poles to radians */
1674
1675 a0 /= CPL_MATH_DEG_RAD;
1676 theta /= CPL_MATH_DEG_RAD;
1677 gal_l0 /= CPL_MATH_DEG_RAD;
1678
1679 /* Do the conversion now */
1680
1681 sindec2 = sin(dec2);
1682 costheta = cos(theta);
1683 sintheta = sin(theta);
1684 cosdra = cos(ra2 - a0);
1685 sindra = sin(ra2 - a0);
1686 x1 = cosdec2*cosdra;
1687 x2 = cosdec2*sindra*costheta + sindec2*sintheta;
1688 *gal_l = atan2(x2,x1) + gal_l0;
1689 if (*gal_l < 0)
1690 *gal_l += CPL_MATH_2PI;
1691 sin_b = sindec2*costheta - cosdec2*sindra*sintheta;
1692 *gal_b = asin(sin_b);
1693}
1694
1695/*---------------------------------------------------------------------------*/
1720/*---------------------------------------------------------------------------*/
1721extern float
1722casu_calculate_abmag_lim(const float zeropoint, const float skynoise,
1723 const float r_core, const float eff_expt, const float apcor3, const float extinction){
1724 return zeropoint - 2.5f * log10f(5.0f * skynoise * r_core * sqrt(CPL_MATH_PI) / eff_expt) - apcor3 - extinction;
1725}
1726
1727extern float
1728casu_calculate_abmag_sat(const float zeropoint, const float satlev,
1729 const float mean_sky, const float psf_fwhm, const float pixel_scale,
1730 const float exptime){
1731 const float val = (CPL_MATH_PI_4 * CPL_MATH_LN2) * (satlev - mean_sky) * powf((psf_fwhm / pixel_scale), 2.0) / exptime;
1732 return zeropoint - 2.5f*log10f(val);
1733}
1734
1737/*
1738
1739$Log: casu_photcal_extinct.c,v $
1740Revision 1.7 2015/09/30 08:33:06 jim
1741superficial changes
1742
1743Revision 1.6 2015/09/14 18:50:07 jim
1744Added missing ABMAGSAT for when calibration fails
1745
1746Revision 1.5 2015/09/11 09:13:41 jim
1747Fixed bug in photometric distortion where pixel size was being calculated
1748incorrectly
1749
1750Revision 1.4 2015/08/07 13:06:54 jim
1751Fixed copyright to ESO
1752
1753Revision 1.3 2015/08/03 12:45:00 jim
1754fixed bug in sizing of schlegel maps
1755
1756Revision 1.2 2015/06/30 17:47:19 jim
1757Added ability to save default zeropoint and error to header if no fit is
1758possible
1759
1760Revision 1.1.1.1 2015/06/12 10:44:32 jim
1761Initial import
1762
1763Revision 1.11 2015/06/03 13:10:57 jim
1764Fixed to remove homegrown WCS routines from distortion correction
1765
1766Revision 1.10 2015/05/13 11:45:35 jim
1767Now adds some extra columns into the matched standards catalogue which
1768might be useful if it is saved
1769
1770Revision 1.9 2015/02/17 11:22:51 jim
1771Fixed to test for existence of extra columns
1772
1773Revision 1.8 2015/02/14 12:33:15 jim
1774matched standards is now a casu_tfits structure with header info
1775
1776Revision 1.7 2015/01/29 11:53:14 jim
1777modified comments and removed extraneous code
1778
1779Revision 1.6 2014/12/11 12:23:33 jim
1780new version
1781
1782Revision 1.5 2014/03/26 15:56:23 jim
1783Removed globals
1784
1785Revision 1.4 2013/11/21 09:38:14 jim
1786detabbed
1787
1788Revision 1.3 2013-10-24 09:25:54 jim
1789traps for dummy input extensions
1790
1791Revision 1.2 2013-09-30 18:11:35 jim
1792Fixed memory error
1793
1794Revision 1.1.1.1 2013-08-27 12:07:48 jim
1795Imported
1796
1797
1798*/
int casu_fits_get_status(casu_fits *p)
Definition: casu_fits.c:711
char * casu_fits_get_fullname(casu_fits *p)
Definition: casu_fits.c:680
cpl_propertylist * casu_fits_get_phu(casu_fits *p)
Definition: casu_fits.c:531
cpl_propertylist * casu_fits_get_ehu(casu_fits *p)
Definition: casu_fits.c:576
int casu_photcal_extinct(casu_fits **images, casu_tfits **mstds, casu_tfits **cats, int nimages, char *filt, cpl_table *phottab, int minstars, cpl_frame *schlf_n, cpl_frame *schlf_s, const char *expkey, const char *amkey, float magerrcut, int *status)
Do photometric calibration.
void casu_medmad(float *data, unsigned char *bpm, long np, float *med, float *mad)
Definition: casu_stats.c:347
cpl_propertylist * casu_tfits_get_ehu(casu_tfits *p)
Definition: casu_tfits.c:473
cpl_propertylist * casu_tfits_get_phu(casu_tfits *p)
Definition: casu_tfits.c:432
cpl_table * casu_tfits_get_table(casu_tfits *p)
Definition: casu_tfits.c:364