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