00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074 #ifdef HAVE_CONFIG_H
00075 # include <config.h>
00076 #endif
00077
00078
00082
00085
00086
00087
00088
00089 #include <uves_response_utils.h>
00090
00091 #include <uves_utils.h>
00092 #include <uves_utils_wrappers.h>
00093 #include <uves_pfits.h>
00094 #include <uves_error.h>
00095 #include <uves_msg.h>
00096
00097 #include <irplib_access.h>
00098 #include <cpl.h>
00099
00100 #include <stdbool.h>
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00130
00131 cpl_image *
00132 uves_calculate_response(const cpl_image *spectrum, const uves_propertylist *spectrum_header,
00133 const cpl_table *flux_table,
00134 const uves_propertylist *raw_header,
00135 double PACCURACY,
00136 bool inverse,
00137 char **ref_obj_id)
00138 {
00139 cpl_image *response = NULL;
00140 cpl_table *catalogue_flux = NULL;
00141 int nx, norders;
00142
00143 nx = cpl_image_get_size_x(spectrum);
00144 norders = cpl_image_get_size_y(spectrum);
00145
00146 response = cpl_image_new(nx, norders, CPL_TYPE_DOUBLE);
00147
00148 check( catalogue_flux = uves_align(raw_header, flux_table, PACCURACY, ref_obj_id),
00149 "Cannot read catalogue flux");
00150
00151
00152 {
00153 double dlambda;
00154 int order;
00155
00156 check( dlambda = uves_pfits_get_cdelt1(spectrum_header),
00157 "Error reading bin width from header");
00158
00159 for (order = 1; order <= norders; order++)
00160 {
00161 double lambda_start;
00162 int x;
00163
00164
00165
00166
00167 if (norders == 1)
00168 {
00169 check( lambda_start = uves_pfits_get_crval1(spectrum_header),
00170 "Error reading start wavelength from header");
00171 }
00172 else
00173 {
00174 check( lambda_start = uves_pfits_get_wstart(spectrum_header, order),
00175 "Error reading start wavelength from header");
00176 }
00177
00178 for (x = 1; x <= nx; x++)
00179 {
00180 int pis_rejected;
00181 double lambda;
00182 double flux, std_flux, resp;
00183 int istart = 0;
00184
00185 lambda = lambda_start + (x-1) * dlambda;
00186
00187 check( flux = cpl_image_get(spectrum, x, order, &pis_rejected),
00188 "Error reading flux");
00189
00190 if (!pis_rejected)
00191 {
00192
00193 check( std_flux = uves_spline_hermite_table(
00194 lambda, catalogue_flux,
00195 "LAMBDA", "F_LAMBDA", &istart),
00196 "Error interpolating catalogue flux");
00197
00198 if (inverse)
00199 {
00200 resp = (flux == 0) ? 0 : std_flux / flux;
00201 }
00202 else
00203 {
00204 resp = (std_flux == 0) ? 0 : flux / std_flux;
00205 }
00206
00207 check( cpl_image_set(response, x, order, resp),
00208 "Error writing response image");
00209 }
00210 else
00211 {
00212 cpl_image_reject(response, x, order);
00213 }
00214 }
00215 }
00216 }
00217
00218 cleanup:
00219 uves_free_table(&catalogue_flux);
00220 if (cpl_error_get_code() != CPL_ERROR_NONE)
00221 {
00222 uves_free_image(&response);
00223 }
00224 return response;
00225 }
00226
00227
00228
00247
00248 cpl_table *
00249 uves_align(const uves_propertylist *object_header, const cpl_table *flux_table,
00250 double accuracy,
00251 char **ref_name_dynamic)
00252 {
00253 double obj_ra, obj_dec;
00254 int nident = 0;
00255 int match_row = 0;
00256 double min_dist = 0;
00257 double std_ra = 0, std_dec = 0;
00258 const char *ref_type = NULL;
00259
00260 cpl_table *result = NULL;
00261
00262 int i;
00263
00264 assure_nomsg( ref_name_dynamic != NULL, CPL_ERROR_NULL_INPUT );
00265 *ref_name_dynamic = NULL;
00266
00267 check( obj_ra = uves_pfits_get_ra (object_header), "Could not read right ascension");
00268 check( obj_dec = uves_pfits_get_dec(object_header), "Could not read declination");
00269
00270 uves_msg("Object RA, DEC = (%e, %e)", obj_ra, obj_dec);
00271
00272 nident = 0;
00273 for (i = 0; i < cpl_table_get_nrow(flux_table); i++)
00274 {
00275 double ref_ra, ref_dec;
00276 double dist;
00277
00278 check( ref_ra = cpl_table_get_double(flux_table, "RA_DEG", i, NULL),
00279 "Could not read catalogue star right ascension");
00280 check( ref_dec = cpl_table_get_double(flux_table, "DEC_DEG", i, NULL),
00281 "Could not read catalogue star declination");
00282
00283
00284
00285
00286
00287
00288
00289 dist =
00290 SIN_DEG(obj_dec)*SIN_DEG(ref_dec) +
00291 COS_DEG(obj_dec)*COS_DEG(ref_dec)*COS_DEG(obj_ra - ref_ra);
00292
00293 dist = uves_max_double(dist, -1);
00294 dist = uves_min_double(dist, 1);
00295
00296 dist = ACOS_DEG(dist) * 3600;
00297
00298 uves_msg_debug("Angular separation = %f arcseconds", dist);
00299
00300
00301
00302 if (i == 0 || dist < min_dist)
00303 {
00304 min_dist = dist;
00305 std_ra = ref_ra;
00306 std_dec = ref_dec;
00307 }
00308
00309
00310
00311 if (dist < accuracy)
00312 {
00313 nident += 1;
00314 match_row = i;
00315 min_dist = dist;
00316 std_ra = ref_ra;
00317 std_dec = ref_dec;
00318 }
00319 }
00320
00321 assure( nident >= 1, CPL_ERROR_INCOMPATIBLE_INPUT,
00322 "No catalogue object within %f arcsecs. "
00323 "Nearest object is %f arcsecs away at (RA, DEC) = (%f, %f)",
00324 accuracy, min_dist, std_ra, std_dec);
00325
00326 assure( nident <= 1, CPL_ERROR_INCOMPATIBLE_INPUT,
00327 "%d matching catalogue objects found. Confused. "
00328 "Decrease pointing accuracy (currently %f arcsecs) to get fewer matches",
00329 nident, accuracy);
00330
00331 check( *ref_name_dynamic = cpl_strdup(
00332 cpl_table_get_string(flux_table, "OBJECT", match_row)),
00333 "Could not read reference object name");
00334
00335 check( ref_type = cpl_table_get_string(flux_table, "TYPE", match_row),
00336 "Could not read reference object type");
00337
00338 uves_msg("Object ID is '%s', type = '%s'. Residual between header/catalogue = %f arcsecs",
00339 *ref_name_dynamic, ref_type, min_dist);
00340
00341
00342
00343 {
00344 const char *columns[3] = {"LAMBDA", "BIN_WIDTH", "F_LAMBDA"};
00345 int ndata;
00346
00347 check( ndata = cpl_table_get_int(flux_table, "NDATA", match_row, NULL),
00348 "Error reading length of flux array");
00349
00350 result = cpl_table_new(ndata);
00351
00352 for(i = 0; i < 3; i++)
00353 {
00354 const cpl_array *data;
00355 int indx;
00356
00357 cpl_table_new_column(result, columns[i], CPL_TYPE_DOUBLE);
00358
00359 data = irplib_table_get_array_const(flux_table, columns[i], match_row);
00360
00361
00362
00363 uves_msg_debug("3d table array size = %d, ndata = %d",
00364 cpl_array_get_size(data), ndata);
00365
00366 assure( cpl_array_get_size(data) >= ndata,
00367 CPL_ERROR_ILLEGAL_INPUT,
00368 "Flux table row %d: column '%s' depth (%d) "
00369 "is less than NDATA (%d)",
00370 match_row, columns[i], cpl_array_get_size(data), ndata);
00371
00372 for (indx = 0; indx < ndata; indx++)
00373 {
00374
00375 cpl_table_set_double(result, columns[i], indx,
00376 cpl_array_get_float(data, indx, NULL));
00377 }
00378 }
00379 }
00380
00381 cleanup:
00382 if (cpl_error_get_code() != CPL_ERROR_NONE)
00383 {
00384 uves_free_table(&result);
00385 if (ref_name_dynamic != NULL)
00386 {
00387 cpl_free(*ref_name_dynamic);
00388 *ref_name_dynamic = NULL;
00389 }
00390 }
00391
00392 return result;
00393 }
00394