GIRAFFE Pipeline Reference Manual

giwlsolution.c
1/*
2 * This file is part of the GIRAFFE Pipeline
3 * Copyright (C) 2002-2019 European Southern Observatory
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#ifdef HAVE_CONFIG_H
21# include <config.h>
22#endif
23
24#include <stdlib.h>
25#include <math.h>
26
27#include <cxmap.h>
28#include <cxstring.h>
29#include <cxstrutils.h>
30
31#include <cpl_error.h>
32#include <cpl_propertylist.h>
33
34#include "gialias.h"
35#include "gierror.h"
36#include "giimage.h"
37#include "gitable.h"
38#include "gichebyshev.h"
39#include "giwlsolution.h"
40
41
50struct GiWlSolution {
51
52 GiModel *model;
53
54 cxbool subslits;
55 GiWlResiduals *residuals;
56
57};
58
59
60inline static GiWlSolution *
61_giraffe_wlsolution_new(const cxchar *name)
62{
63
64 GiWlSolution *self = cx_calloc(1, sizeof *self);
65
66
67 if (self) {
68
69 self->model = giraffe_model_new(name);
70
71 if (self->model == NULL) {
72 giraffe_wlsolution_delete(self);
73 return NULL;
74 }
75
76 if (giraffe_model_get_type(self->model) != GI_MODEL_XOPT) {
77 giraffe_wlsolution_delete(self);
78 return NULL;
79 }
80
81 self->subslits = FALSE;
82 self->residuals = NULL;
83
84 }
85
86 return self;
87
88}
89
90
91GiWlSolution *
92giraffe_wlsolution_new(const cxchar *name, cxint orientation, cxint npixels,
93 cxdouble pixelsize, GiGrating *grating)
94{
95
96 GiWlSolution *self = NULL;
97
98
99 if (name == NULL) {
100 return self;
101 }
102
103 if (grating == NULL) {
104 return self;
105 }
106
107
108 self = _giraffe_wlsolution_new(name);
109
110 if (self) {
111
112 orientation = orientation < 0 ? -npixels : npixels;
113 pixelsize /= 1000.;
114
115 giraffe_error_push();
116
117 giraffe_model_set_parameter(self->model, "Orientation",
118 orientation);
119 giraffe_model_set_parameter(self->model, "Order",
120 grating->order);
121 giraffe_model_set_parameter(self->model, "PixelSize",
122 pixelsize);
123 giraffe_model_set_parameter(self->model, "FocalLength",
124 grating->fcoll);
125 giraffe_model_set_parameter(self->model, "Magnification",
126 grating->gcam);
127 giraffe_model_set_parameter(self->model, "Angle",
128 grating->theta);
129 giraffe_model_set_parameter(self->model, "Spacing",
130 grating->space);
131
132 if (strcmp(name, "xoptmod2") == 0) {
133
134 giraffe_model_set_parameter(self->model, "Sdx", grating->sdx);
135 giraffe_model_set_parameter(self->model, "Sdy", grating->sdy);
136 giraffe_model_set_parameter(self->model, "Sphi", grating->sphi);
137
138 }
139
140 if (cpl_error_get_code() != CPL_ERROR_NONE) {
141 giraffe_wlsolution_delete(self);
142 return NULL;
143 }
144
145 giraffe_error_pop();
146
147 }
148
149 return self;
150
151}
152
153
167GiWlSolution *
168giraffe_wlsolution_clone(const GiWlSolution *other)
169{
170
171 GiWlSolution *self = NULL;
172
173
174 if (other != NULL) {
175
176 self = cx_calloc(1, sizeof(GiWlSolution));
177
178 self->model = giraffe_model_clone(other->model);
179
180 self->subslits = other->subslits;
181 self->residuals = giraffe_wlresiduals_clone(other->residuals);
182
183 }
184
185 return self;
186
187}
188
189
205GiWlSolution *
206giraffe_wlsolution_create(GiTable *solution, GiImage *spectra,
207 GiGrating *grating)
208{
209
210 const cxchar *name = NULL;
211
212 cxint npixels = 0;
213 cxint orientation = 0;
214
215 cxdouble pixelsize = 0.;
216 cxdouble fcoll = 0.;
217 cxdouble gcam = 0.;
218 cxdouble theta = 0.;
219 cxdouble sdx = 0.;
220 cxdouble sdy = 0.;
221 cxdouble sphi = 0.;
222
223
224 cpl_propertylist *properties = NULL;
225
226 GiWlSolution *self = NULL;
227
228
229
230 if (solution == NULL) {
231 return NULL;
232 }
233
234 if (giraffe_table_get_properties(solution) == NULL) {
235 return NULL;
236 }
237
238 if (giraffe_table_get(solution) == NULL) {
239 return NULL;
240 }
241
242
243 if (spectra == NULL) {
244 return NULL;
245 }
246
247 if (giraffe_image_get_properties(spectra) == NULL) {
248 return NULL;
249 }
250
251 if (giraffe_image_get(spectra) == NULL) {
252 return NULL;
253 }
254
255
256 if (grating == NULL) {
257 return NULL;
258 }
259
260
261 /*
262 * Setup the optical model from the wavelength solution table properties,
263 * the grating setup and the reference spectrum.
264 */
265
266 /*
267 * Reference image: number of pixels and pixel size
268 */
269
270 properties = giraffe_image_get_properties(spectra);
271
272 if (!cpl_propertylist_has(properties, GIALIAS_PIXSIZX)) {
273 return NULL;
274 }
275 else {
276
277 /*
278 * Get pixel size and convert it from microns to mm.
279 */
280
281 pixelsize = cpl_propertylist_get_double(properties, GIALIAS_PIXSIZX);
282 pixelsize /= 1000.;
283
284 }
285
286 npixels = cpl_image_get_size_y(giraffe_image_get(spectra));
287
288
289 /*
290 * Wavelength solution properties: orientation, collimator focal
291 * length, camera magnification, grating angle and slit offsets.
292 */
293
294 properties = giraffe_table_get_properties(solution);
295
296
297 if (!cpl_propertylist_has(properties, GIALIAS_WSOL_OMNAME)) {
298 return NULL;
299 }
300 else {
301 name = cpl_propertylist_get_string(properties, GIALIAS_WSOL_OMNAME);
302 }
303
304
305 self = _giraffe_wlsolution_new(name);
306
307 if (self) {
308
309 if (!cpl_propertylist_has(properties, GIALIAS_WSOL_SUBSLITS)) {
310 giraffe_wlsolution_delete(self);
311 return NULL;
312 }
313 else {
314
315 self->subslits = cpl_propertylist_get_bool(properties,
316 GIALIAS_WSOL_SUBSLITS);
317
318 }
319
320 if (!cpl_propertylist_has(properties, GIALIAS_WSOL_OMDIR)) {
321 giraffe_wlsolution_delete(self);
322 return NULL;
323 }
324 else {
325 orientation = cpl_propertylist_get_int(properties,
326 GIALIAS_WSOL_OMDIR);
327 orientation = orientation < 0 ? -fabs(npixels) : fabs(npixels);
328 }
329
330
331 if (!cpl_propertylist_has(properties, GIALIAS_WSOL_OMFCOLL)) {
332 giraffe_wlsolution_delete(self);
333 return NULL;
334 }
335 else {
336 fcoll = cpl_propertylist_get_double(properties,
337 GIALIAS_WSOL_OMFCOLL);
338 }
339
340
341 if (!cpl_propertylist_has(properties, GIALIAS_WSOL_OMGCAM)) {
342 giraffe_wlsolution_delete(self);
343 return NULL;
344 }
345 else {
346 gcam = cpl_propertylist_get_double(properties,
347 GIALIAS_WSOL_OMGCAM);
348 }
349
350
351 if (!cpl_propertylist_has(properties, GIALIAS_WSOL_OMGTHETA)) {
352 giraffe_wlsolution_delete(self);
353 return NULL;
354 }
355 else {
356 theta = cpl_propertylist_get_double(properties,
357 GIALIAS_WSOL_OMGTHETA);
358 }
359
360
361 if (strcmp(name, "xoptmod2") == 0) {
362
363 if (!cpl_propertylist_has(properties, GIALIAS_WSOL_OMSDX)) {
364 giraffe_wlsolution_delete(self);
365 return NULL;
366 }
367 else {
368 sdx = cpl_propertylist_get_double(properties,
369 GIALIAS_WSOL_OMSDX);
370 }
371
372
373 if (!cpl_propertylist_has(properties, GIALIAS_WSOL_OMSDY)) {
374 giraffe_wlsolution_delete(self);
375 return NULL;
376 }
377 else {
378 sdy = cpl_propertylist_get_double(properties,
379 GIALIAS_WSOL_OMSDY);
380 }
381
382
383 if (!cpl_propertylist_has(properties, GIALIAS_WSOL_OMSPHI)) {
384 giraffe_wlsolution_delete(self);
385 return NULL;
386 }
387 else {
388 sphi = cpl_propertylist_get_double(properties,
389 GIALIAS_WSOL_OMSPHI);
390 }
391
392 }
393
394
395 /*
396 * Initialize the optical model parameters
397 */
398
399 giraffe_error_push();
400
401 giraffe_model_set_parameter(self->model, "Orientation", orientation);
402 giraffe_model_set_parameter(self->model, "Order", grating->order);
403 giraffe_model_set_parameter(self->model, "PixelSize", pixelsize);
404 giraffe_model_set_parameter(self->model, "FocalLength", fcoll);
405 giraffe_model_set_parameter(self->model, "Magnification", gcam);
406 giraffe_model_set_parameter(self->model, "Angle", theta);
407 giraffe_model_set_parameter(self->model, "Spacing", grating->space);
408
409 if (strcmp(name, "xoptmod2") == 0) {
410 giraffe_model_set_parameter(self->model, "Sdx", sdx);
411 giraffe_model_set_parameter(self->model, "Sdy", sdy);
412 giraffe_model_set_parameter(self->model, "Sphi", sphi);
413 }
414
415 if (cpl_error_get_code() != CPL_ERROR_NONE) {
416 giraffe_wlsolution_delete(self);
417 return NULL;
418 }
419
420 giraffe_error_pop();
421
422
423 /*
424 * Get the wavelength residuals fit coefficients from the wavelength
425 * solution table.
426 */
427
428 self->residuals = giraffe_wlresiduals_create(solution);
429
430 if (self->residuals == NULL) {
431 self->subslits = FALSE;
432 }
433
434 }
435
436 return self;
437
438}
439
440
441void
442giraffe_wlsolution_delete(GiWlSolution *self)
443{
444
445 if (self != NULL) {
446
447 if (self->model != NULL) {
448 giraffe_model_delete(self->model);
449 }
450
451 if (self->residuals != NULL) {
452 giraffe_wlresiduals_delete(self->residuals);
453 }
454
455 cx_free(self);
456
457 }
458
459 return;
460
461}
462
463
464const cxchar *
465giraffe_wlsolution_name(const GiWlSolution *self)
466{
467
468 GiModel *model = NULL;
469
470
471 cx_assert(self != NULL);
472
473 model = self->model;
474 cx_assert(model != NULL);
475
476 return giraffe_model_get_name(model);
477
478}
479
480
481GiModel *
482giraffe_wlsolution_model(const GiWlSolution *self)
483{
484
485 cx_assert(self != NULL);
486
487 return self->model;
488
489}
490
491
492cxint
493giraffe_wlsolution_set_subslits(GiWlSolution *self, cxbool flag)
494{
495
496 cx_assert(self != NULL);
497
498 if (self->residuals != NULL) {
499 return 1;
500 }
501
502 self->subslits = flag;
503
504 return 0;
505
506}
507
508
509cxbool
510giraffe_wlsolution_get_subslits(const GiWlSolution *self)
511{
512
513 cx_assert(self != NULL);
514
515 return self->subslits;
516
517}
518
519
520cxint
521giraffe_wlsolution_set_residuals(GiWlSolution *self,
522 const GiWlResiduals *residuals)
523{
524
525 cxbool subslits = FALSE;
526
527
528 cx_assert(self != NULL);
529
530 if (residuals == NULL) {
531 return 1;
532 }
533
534
535 /* FIXME: This is a very weak check whether the residuals to accept
536 * are valid for the current subslits flag setting. A better
537 * mechanism needs to be put here, but this needs to be supported
538 * by the GiWlResidual class.
539 */
540
541 subslits = giraffe_wlresiduals_get(residuals, 0) == NULL;
542
543 if (self->subslits != subslits) {
544 return 2;
545 }
546
547 giraffe_wlsolution_reset_residuals(self);
548
549 self->residuals = (GiWlResiduals *)residuals;
550
551 return 0;
552
553}
554
555
556GiWlResiduals *
557giraffe_wlsolution_get_residuals(const GiWlSolution *self)
558{
559
560 cx_assert(self != NULL);
561
562 return self->residuals;
563
564}
565
566
567void
568giraffe_wlsolution_reset_residuals(GiWlSolution *self)
569{
570
571 cx_assert(self != NULL);
572
573 if (self->residuals != NULL) {
574 giraffe_wlresiduals_delete(self->residuals);
575 self->residuals = NULL;
576 }
577
578 return;
579
580}
581
582
583cxdouble
584giraffe_wlsolution_compute_pixel(const GiWlSolution *self, cxdouble lambda,
585 cxdouble x, cxdouble y, cxint *status)
586{
587
588 cxint code = 0;
589 cxint _status = 0;
590
591 cxdouble result = 0.;
592
593
594 cx_assert(self != NULL);
595
596 giraffe_error_push();
597
598 giraffe_model_set_argument(self->model, "xf", x);
599 giraffe_model_set_argument(self->model, "yf", y);
600 giraffe_model_set_argument(self->model, "lambda", lambda);
601
602 if (cpl_error_get_code() != CPL_ERROR_NONE) {
603
604 if (status != NULL) {
605 *status = -128;
606 }
607
608 return result;
609 }
610
611 giraffe_error_pop();
612
613 code = giraffe_model_evaluate(self->model, &result, &_status);
614
615 if (code != 0) {
616
617 if (status != NULL) {
618 *status = -128;
619 }
620
621 return result;
622
623 }
624
625 if (status != NULL) {
626 *status = _status;
627 }
628
629 return result;
630
631}
632
633
634cxdouble
635giraffe_wlsolution_compute_residual(const GiWlSolution *self, cxdouble x,
636 cxdouble y)
637{
638
639 cxint i;
640
641 cxdouble r = 0.;
642
643 const GiWlResiduals *residuals = NULL;
644
645
646 cx_assert(self != NULL);
647
648 residuals = giraffe_wlsolution_get_residuals(self);
649
650 if (residuals == NULL) {
651 return r;
652 }
653
654
655 /*
656 * Find first residual fit with matching ranges. This is used
657 * for the residual computation assuming that the intervals
658 * for which the fits are valid do not overlap.
659 */
660
661 for (i = 0; (cxsize)i < giraffe_wlresiduals_get_size(residuals); i++) {
662
663 const GiChebyshev2D *fit = giraffe_wlresiduals_get(residuals, i);
664
665 if (fit != NULL) {
666
667 cxdouble ax;
668 cxdouble bx;
669 cxdouble ay;
670 cxdouble by;
671
672 giraffe_chebyshev2d_get_range(fit, &ax, &bx, &ay, &by);
673
674 if (ax <= x && x <= bx && ay <= y && y <= by) {
675 r = giraffe_chebyshev2d_eval(fit, x, y);
676 break;
677 }
678
679 }
680
681 }
682
683 return r;
684
685}
686
687
688GiTable *
689giraffe_wlsolution_create_table(const GiWlSolution *solution)
690{
691
692
693 cxint sign = 1;
694
695 cxdouble value = 0.;
696
697 cpl_propertylist *properties = NULL;
698
699 GiTable *result = NULL;
700
701 const GiModel *model = NULL;
702
703 const GiWlResiduals *residuals = NULL;
704
705
706 if (solution == NULL) {
707 return NULL;
708 }
709
710
711 result = giraffe_table_new();
712 cx_assert(result != NULL);
713
714 properties = cpl_propertylist_new();
715 cx_assert(properties != NULL);
716
717
718 /*
719 * Build up wavelength solution properties
720 */
721
722 cpl_propertylist_update_string(properties, GIALIAS_GIRFTYPE,
723 "WLSOLUTION");
724 cpl_propertylist_set_comment(properties, GIALIAS_GIRFTYPE,
725 "Giraffe frame type.");
726
727 cpl_propertylist_update_string(properties, GIALIAS_WSOL_OMNAME,
728 giraffe_wlsolution_name(solution));
729 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_OMNAME,
730 "Optical model name");
731
732 model = giraffe_wlsolution_model(solution);
733
734 sign = giraffe_model_get_parameter(model,"Orientation") < 0 ? -1 : 1;
735 cpl_propertylist_update_int(properties, GIALIAS_WSOL_OMDIR, sign);
736 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_OMDIR,
737 "Optical model orientation");
738
739 value = giraffe_model_get_parameter(model, "FocalLength");
740 cpl_propertylist_update_double(properties, GIALIAS_WSOL_OMFCOLL, value);
741 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_OMFCOLL,
742 "Optical model focal length");
743
744 value = giraffe_model_get_parameter(model, "Magnification");
745 cpl_propertylist_update_double(properties, GIALIAS_WSOL_OMGCAM, value);
746 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_OMGCAM,
747 "Optical model camera factor");
748
749 value = giraffe_model_get_parameter(model, "Angle");
750 cpl_propertylist_update_double(properties, GIALIAS_WSOL_OMGTHETA,
751 value);
752 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_OMGTHETA,
753 "Optical model grating angle");
754
755 if (strcmp(giraffe_wlsolution_name(solution), "xoptmod2") == 0) {
756
757 value = giraffe_model_get_parameter(model, "Sdx");
758 cpl_propertylist_update_double(properties, GIALIAS_WSOL_OMSDX,
759 value);
760 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_OMSDX,
761 "Optical model slit x-offset");
762
763 value = giraffe_model_get_parameter(model, "Sdy");
764 cpl_propertylist_update_double(properties, GIALIAS_WSOL_OMSDY,
765 value);
766 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_OMSDY,
767 "Optical model slit y-offset");
768
769 value = giraffe_model_get_parameter(model, "Sphi");
770 cpl_propertylist_update_double(properties, GIALIAS_WSOL_OMSPHI,
771 value);
772 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_OMSPHI,
773 "Optical model slit rotation");
774
775 }
776
777
778 /*
779 * Add optical model residuals fit coefficients, if they are present
780 * in the wavelength solution.
781 */
782
783 residuals = giraffe_wlsolution_get_residuals(solution);
784
785 if (residuals != NULL) {
786
787 cpl_table *coeffs = giraffe_wlresiduals_table(residuals);
788
789 if (coeffs != NULL) {
790 giraffe_table_set(result, coeffs);
791 }
792
793 }
794
795 giraffe_table_set_properties(result, properties);
796
797 cpl_propertylist_delete(properties);
798 properties = NULL;
799
800 return result;
801
802}
cpl_image * giraffe_image_get(const GiImage *self)
Gets the image data.
Definition: giimage.c:218
cpl_propertylist * giraffe_image_get_properties(const GiImage *self)
Get the properties of an image.
Definition: giimage.c:282
cxint giraffe_table_set(GiTable *self, cpl_table *table)
Sets the table data.
Definition: gitable.c:456
GiTable * giraffe_table_new(void)
Creates a new, empty Giraffe table.
Definition: gitable.c:85
cpl_table * giraffe_table_get(const GiTable *self)
Get the table data from a Giraffe table.
Definition: gitable.c:433
cpl_propertylist * giraffe_table_get_properties(const GiTable *self)
Gets the table properties.
Definition: gitable.c:489
cxint giraffe_table_set_properties(GiTable *self, cpl_propertylist *properties)
Attaches a property list to an table.
Definition: gitable.c:516
GiWlSolution * giraffe_wlsolution_create(GiTable *solution, GiImage *spectra, GiGrating *grating)
Create a new wavelength solution from a wavelength solution table.
Definition: giwlsolution.c:206
GiWlSolution * giraffe_wlsolution_clone(const GiWlSolution *other)
Create a new wavelength solution from another wavelength solution.
Definition: giwlsolution.c:168
Structure to handle Grating Information.
Definition: gigrating.h:44
cxdouble sdy
Definition: gigrating.h:60
cxdouble space
Definition: gigrating.h:55
cxdouble fcoll
Definition: gigrating.h:57
cxdouble sdx
Definition: gigrating.h:59
cxdouble gcam
Definition: gigrating.h:58
cxdouble sphi
Definition: gigrating.h:61
cxint order
Definition: gigrating.h:49
cxdouble theta
Definition: gigrating.h:56

This file is part of the GIRAFFE Pipeline Reference Manual 2.16.14.
Documentation copyright © 2002-2006 European Southern Observatory.
Generated on Wed Jun 11 2025 18:28:29 by doxygen 1.9.6 written by Dimitri van Heesch, © 1997-2004