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