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