sinfo_atmo_disp.c

00001 /*
00002  * This file is part of the ESO SINFONI Pipeline
00003  * Copyright (C) 2004-2009 European Southern Observatory
00004  *
00005  * This program is free software; you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License as published by
00007  * the Free Software Foundation; either version 2 of the License, or
00008  * (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program; if not, write to the Free Software
00017  * Foundation, 51 Franklin St, Fifth Floor, Boston, MA  02111-1307  USA
00018  */
00019 
00020 /*
00021  * $Author: amodigli $
00022  * $Date: 2011/12/08 16:15:40 $
00023  * $Revision: 1.7 $
00024  */
00025 
00026 #ifdef HAVE_CONFIG_H
00027 #include <config.h>          /* allows the program compilation */
00028 #endif
00029 
00030 #include <cpl.h>
00031 #include <string.h>
00032 #include <math.h>
00033 #include <sinfo_msg.h>
00034 #include <sinfo_utils_wrappers.h>
00035 #include "sinfo_atmo_disp.h"
00036 #include "sinfo_resampling.h"
00037 #include "sinfo_image_ops.h"
00038 
00039 struct _disp_data
00040 {
00041     double p1;
00042     double d1;
00043     double d2;
00044     double N0;
00045     double predelta;
00046     double parallactic_shiftX;
00047     double parallactic_shiftY;
00048 };
00049 typedef struct _disp_data disp_data;
00050 static double sinfo_disp_calc_N(const disp_data* pdata, double lambda);
00051 static void 
00052 sinfo_disp_prepare_data(disp_data* pdata,
00053             double lambda0,
00054             double Tc,
00055             double rh,
00056             double airm,
00057             double p,
00058             double parallactic,
00059             double pixelscale );
00060 
00061 static void 
00062 sinfo_disp_calc(disp_data* pdata, double lambda, double *shiftx, double *shiftY);
00063 static void 
00064 sinfo_atmo_rotate_point(double* x_value, double * y_value, double rot_angle);
00065 /*------------------------------------------------------------------------------------*/
00066 
00067 static double 
00068 sinfo_disp_calc_N(const disp_data* pdata, double lambda)
00069 {
00070     double s = 1.0 /lambda;
00071     double s2 = s  * s;
00072     double s3 = s2 * s;
00073     double s4 = s3 * s;
00074     double s5 = s4 * s;
00075     double s6 = s5 * s;
00076 
00077     double a = 83939.7/(130   - s2);
00078     double b =   4547.3/(38.99 - s2);
00079     double c = 6487.31 + 58.058*s2 - 0.71150*s4 + 0.08851*s6;
00080     double N =  1e-8 * ( ((2371.34 + a + b) * pdata->d1)  +  ( c * pdata->d2));
00081     return N;
00082 
00083 }
00084 static void 
00085 sinfo_disp_prepare_data(disp_data* pdata,
00086         double lambda0,
00087         double Tc,
00088         double rh,
00089         double airm,
00090         double p,
00091         double parallactic,
00092         double pixelscale )
00093 {
00094     double ps,p2,p1,T,T2,T3;
00095     double zenith;
00096 //    const double PI_NUMBer = 3.1415926535;
00097 
00098     T  = Tc + 273.15;T2 = T  * T; T3 = T2 * T;
00099     ps = -10474 + (116.43 * T) - (0.43284 *T2) + (0.00053840 * T3);
00100     p2 = (rh/100)*ps;
00101     p1 = p - p2;
00102     pdata->d1 = (p1/T)*(1+p1*( (57.90e-8) - ((9.3250e-4)/T) + (0.25844/T2)));
00103     pdata->d2 = (p2/T)*(1+p2*(1+3.7e-4*p2)*( (-2.37321e-3) + (2.23366/T) - (710.792/T2) + ((7.75141e-4)/T3) )) ;
00104     pdata->N0 = sinfo_disp_calc_N(pdata, lambda0);
00105     zenith     = acos(1/airm);
00106     pdata->predelta      = ((tan(zenith)) / (PI_NUMB/180)) * 3600;
00107     pdata->parallactic_shiftX = sin ( (parallactic)* (PI_NUMB/180) ) / pixelscale;
00108     pdata->parallactic_shiftY = cos ( (parallactic)* (PI_NUMB/180) ) / pixelscale;
00109     sinfo_msg_warning("atm disp N0[%f] d1[%f] d2[%f] pshiftX[%f] pshiftY[%f]",
00110             pdata->N0,pdata->d1, pdata->d2,  pdata->parallactic_shiftX ,
00111             pdata->parallactic_shiftY);
00112 }
00113 static void 
00114 sinfo_disp_calc(disp_data* pdata, double lambda, double *shiftx, double *shifty)
00115 {
00116     double n = sinfo_disp_calc_N(pdata, lambda);
00117     double delta = pdata->predelta * (n - pdata->N0);
00118     *shiftx = -delta * pdata->parallactic_shiftX;
00119     *shifty = delta * pdata->parallactic_shiftY ;
00120 }
00121 
00122 cpl_error_code 
00123 sinfo_atm_dispersion_cube(cpl_imagelist* pCube,
00124         int centpix, // central plane in the cube CRPIX3
00125         double centlambda, // wavelength of the central plane CRVAL3
00126         double Tc, // temperature in Celsius TEL.AMBI.TEMP
00127         double Rh, // relative humidity in % TEL.AMBI.RHUM
00128         double airm, // airmass for the moment of observation TEL.AMBI.PRES
00129         double p, // atmospheric pressure TEL.AMBI.PRES
00130         double parallactic, // TEL.PARANG
00131         double pixelscale, // could be for SINFONI 0.025, 0.100, 0.250
00132         double pixelsz // microns per pixel CDELT3
00133         )
00134 {
00135     cpl_error_code err = CPL_ERROR_NONE;
00136     int cubesize = cpl_imagelist_get_size(pCube);
00137     double * kernel = sinfo_generate_interpolation_kernel("default");
00138     disp_data ddata;
00139     int i = 0;
00140 
00141     sinfo_disp_prepare_data(&ddata, centlambda, Tc, Rh, airm, p, parallactic, pixelscale);
00142 
00143     for (i = 0; i < cubesize; i++)
00144     {
00145         double shiftx = 0;
00146         double shifty = 0;
00147 
00148         cpl_image* pnewImage = 0;
00149         // 1. get an image
00150         cpl_image* plane = cpl_imagelist_get(pCube, i);
00151 
00152         // 2. calculate dispersion and shift
00153         double lambda = centlambda - (centpix - i) * pixelsz;
00154         sinfo_disp_calc(&ddata, lambda, &shiftx, &shifty);
00155         // 3. aplly shift
00156 //      int szx = cpl_image_get_size_x(plane);
00157         //int szy = cpl_image_get_size_y(plane);
00158         //if (i % 10 == 0)
00159             sinfo_msg_warning(" shift image #%d, dx[%f] dy[%f]", i, shiftx, shifty);
00160         pnewImage = sinfo_new_shift_image(
00161             plane,
00162             shiftx,
00163             shifty,
00164             kernel);
00165         err = cpl_imagelist_set(pCube, pnewImage, i);
00166         if (err != CPL_ERROR_NONE)
00167             break;
00168     }
00169     cpl_free(kernel);
00170     return err;
00171 
00172 }
00173 
00174 
00175 /*----------------------------------------------------
00176  * Atmospheric correction using polynomial fit
00177  *----------------------------------------------------*/
00178 cpl_polynomial* 
00179 sinfo_atmo_load_polynom(const char* filename)
00180 {
00181     const char* COL_NAME_TEMPLATE = "col_%d";
00182     const char* COL_NAME_VALUE = "value";
00183     cpl_polynomial* poly = NULL;
00184     cpl_table* ptable = NULL;
00185 
00186     ptable = cpl_table_load(filename, 1, 0);
00187     if (ptable)
00188     {
00189         int dim = 0;
00190         int nrows = 0;
00191         int i = 0;
00192         cpl_size* expo = NULL;
00193 
00194         dim = cpl_table_get_ncol(ptable) - 1;
00195         poly = cpl_polynomial_new(dim );
00196         nrows = cpl_table_get_nrow(ptable);
00197         expo = cpl_malloc(dim * sizeof(expo[0]));
00198         memset(&expo[0], 0, dim * sizeof(expo[0]));
00199         for (i = 0; i < nrows; i++)
00200         {
00201             int j = 0;
00202             int inull = 0;
00203             double value = 0;
00204             for (j = 0; j < dim; j++)
00205             {
00206                 char col_name[255];
00207                 sprintf(col_name, COL_NAME_TEMPLATE, j);
00208                 expo[j] = cpl_table_get_int(ptable, col_name, i, &inull);
00209             }
00210             value = cpl_table_get(ptable, COL_NAME_VALUE, i, &inull);
00211             cpl_polynomial_set_coeff(poly, expo, value);
00212             if (cpl_error_get_code() != CPL_ERROR_NONE)
00213             {
00214                 if (poly)
00215                 {
00216                     sinfo_free_polynomial(&poly);
00217                 }
00218                 break;
00219             }
00220         }
00221         cpl_free(expo);
00222     }
00223     sinfo_free_table(&ptable);
00224     return poly;
00225 }
00226 
00227 static void 
00228 sinfo_atmo_rotate_point(double* x_value, double * y_value, double rot_angle)
00229 {
00230     double newx = *x_value * cos(rot_angle) - *y_value * sin(rot_angle);
00231     double newy = *x_value * sin(rot_angle) + *y_value * cos(rot_angle);
00232     *x_value = newx;
00233     *y_value = newy;
00234 }
00235 
00236 cpl_imagelist* 
00237 sinfo_atmo_apply_cube_polynomial_shift(
00238         cpl_polynomial* poly,
00239         cpl_imagelist* pCube,
00240         double lambda0,
00241         double airmass,
00242         double parallactic, // should be in radian
00243         double pixelsz,
00244         int centpix)
00245 {
00246     cpl_imagelist* retcube = NULL;
00247     cpl_error_code  err = CPL_ERROR_NONE;
00248     cpl_vector* vparams = NULL;
00249     double * kernel = sinfo_generate_interpolation_kernel("default");
00250     int cubesize = 0;
00251     int i = 0;
00252     // the following two parameters are necessary for computing the shift
00253     // in case when polynom for H+K band is used for H or K
00254     double l0_shift_x = 0; // shift for the central point by X
00255     double l0_shift_y = 0; // shift for the central point by Y
00256 
00257     vparams = cpl_vector_new(2);
00258     cpl_vector_set(vparams, 0, airmass);
00259     cpl_vector_set(vparams, 1, lambda0);
00260     err = cpl_error_get_code();
00261     if (err == CPL_ERROR_NONE)
00262     {
00263         l0_shift_y = cpl_polynomial_eval(poly, vparams); // North - South
00264         l0_shift_x = 0; // (EAST-WEST direction)
00265         // rotate the shift
00266         sinfo_atmo_rotate_point(&l0_shift_x, &l0_shift_y, parallactic);
00267         cubesize = cpl_imagelist_get_size(pCube);
00268         err =  cpl_error_get_code();
00269     }
00270     if (err == CPL_ERROR_NONE)
00271     {
00272         retcube = cpl_imagelist_new();
00273         for (i = 0; i < cubesize; i++)
00274         {
00275             // calculate the wavelength
00276             double lambda = lambda0 - (centpix - i) * pixelsz;
00277             double shift_y = 0;
00278             double shift_x = 0;
00279 
00280             cpl_vector_set(vparams, 1, lambda);
00281             // calc the shift
00282             shift_y = cpl_polynomial_eval(poly, vparams); // North - South
00283             err = cpl_error_get_code();
00284             if (err == CPL_ERROR_NONE)
00285             {
00286                 double res_shift_x = -(shift_x - l0_shift_x);
00287                 double res_shift_y = -(shift_y - l0_shift_y);
00288                 cpl_image* plane = NULL;
00289                 cpl_image* pimresult = NULL;
00290                 // rotate the shift
00291                 sinfo_atmo_rotate_point(&res_shift_x, &res_shift_y, parallactic);
00292                 plane = cpl_imagelist_get(pCube, i);
00293                 pimresult = sinfo_new_shift_image(
00294                         plane,
00295                         res_shift_x, // x shift
00296                         res_shift_y, // y shift
00297                         kernel);
00298                 if (err == CPL_ERROR_NONE)
00299                 {
00300                     err = cpl_imagelist_set(retcube, pimresult, i);
00301                 }
00302                 else
00303                 {
00304                     sinfo_msg_error("Error sinfo_new_shift_image, %s",
00305                                         cpl_error_get_where());
00306                 }
00307                 if (err != CPL_ERROR_NONE)
00308                     break;
00309             }
00310             else
00311             {
00312                 sinfo_msg_error("Error polynomial_eval, %s",
00313                         cpl_error_get_where());
00314             }
00315             if (err != CPL_ERROR_NONE)
00316                 break;
00317         }
00318     }
00319     if (err != CPL_ERROR_NONE)
00320     {
00321         sinfo_free_imagelist(&retcube);
00322         sinfo_msg_error("Error during shift planes in the cube, %s",
00323                 cpl_error_get_where());
00324     }
00325     sinfoni_free_vector(&vparams);
00326     cpl_free(kernel);
00327     return retcube;
00328 }

Generated on 3 Mar 2013 for SINFONI Pipeline Reference Manual by  doxygen 1.6.1