VIRCAM Pipeline  2.3.10
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 
44 typedef 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 
62 static double pixsize (cpl_propertylist *plist);
63 static int casu_phot_open(cpl_table *phottab, char *filt, photstrct *p);
64 static void casu_phot_close(photstrct *p);
65 static int extract_columns(cpl_table *tab, photstrct *p);
66 static int extract_coleq(cpl_table *tab, photstrct *p);
67 static 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);
70 static void modifytab(photstrct *p, cpl_table *intab, casu_fits *im,
71  int minstars, cpl_image *schl_n, cpl_image *schl_s);
72 static void getextinct(cpl_image *schl_n, cpl_image *schl_s, double ra,
73  double dec, float *ebv);
74 static void radectolb(double ra, double dec, float epoch, double *gal_l,
75  double *gal_b);
76 static void photdistort(casu_fits *im, cpl_table *outtab);
77 static void getproj_pixsize(cpl_wcs *wcs, double crv1, double tand,
78  double secd, double x, double y, double *pixsize);
79 
80 static 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 
198 extern 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 /*---------------------------------------------------------------------------*/
786 extern 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 
841 static 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 
879 static 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 
972 static 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 
1005 static 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 
1077 static 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 
1152 static 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 
1248 static 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 
1356 static 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 /*---------------------------------------------------------------------------*/
1417 static 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 
1460 static 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 
1551 static 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 
1626 static 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 /*---------------------------------------------------------------------------*/
1721 extern float
1722 casu_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 
1727 extern float
1728 casu_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 $
1740 Revision 1.7 2015/09/30 08:33:06 jim
1741 superficial changes
1742 
1743 Revision 1.6 2015/09/14 18:50:07 jim
1744 Added missing ABMAGSAT for when calibration fails
1745 
1746 Revision 1.5 2015/09/11 09:13:41 jim
1747 Fixed bug in photometric distortion where pixel size was being calculated
1748 incorrectly
1749 
1750 Revision 1.4 2015/08/07 13:06:54 jim
1751 Fixed copyright to ESO
1752 
1753 Revision 1.3 2015/08/03 12:45:00 jim
1754 fixed bug in sizing of schlegel maps
1755 
1756 Revision 1.2 2015/06/30 17:47:19 jim
1757 Added ability to save default zeropoint and error to header if no fit is
1758 possible
1759 
1760 Revision 1.1.1.1 2015/06/12 10:44:32 jim
1761 Initial import
1762 
1763 Revision 1.11 2015/06/03 13:10:57 jim
1764 Fixed to remove homegrown WCS routines from distortion correction
1765 
1766 Revision 1.10 2015/05/13 11:45:35 jim
1767 Now adds some extra columns into the matched standards catalogue which
1768 might be useful if it is saved
1769 
1770 Revision 1.9 2015/02/17 11:22:51 jim
1771 Fixed to test for existence of extra columns
1772 
1773 Revision 1.8 2015/02/14 12:33:15 jim
1774 matched standards is now a casu_tfits structure with header info
1775 
1776 Revision 1.7 2015/01/29 11:53:14 jim
1777 modified comments and removed extraneous code
1778 
1779 Revision 1.6 2014/12/11 12:23:33 jim
1780 new version
1781 
1782 Revision 1.5 2014/03/26 15:56:23 jim
1783 Removed globals
1784 
1785 Revision 1.4 2013/11/21 09:38:14 jim
1786 detabbed
1787 
1788 Revision 1.3 2013-10-24 09:25:54 jim
1789 traps for dummy input extensions
1790 
1791 Revision 1.2 2013-09-30 18:11:35 jim
1792 Fixed memory error
1793 
1794 Revision 1.1.1.1 2013-08-27 12:07:48 jim
1795 Imported
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_table * casu_tfits_get_table(casu_tfits *p)
Definition: casu_tfits.c:364
cpl_propertylist * casu_tfits_get_phu(casu_tfits *p)
Definition: casu_tfits.c:432
cpl_propertylist * casu_tfits_get_ehu(casu_tfits *p)
Definition: casu_tfits.c:473