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 
50 struct GiWlSolution {
51 
52  GiModel *model;
53 
54  cxbool subslits;
55  GiWlResiduals *residuals;
56 
57 };
58 
59 
60 inline 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 
91 GiWlSolution *
92 giraffe_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 
167 GiWlSolution *
168 giraffe_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 
205 GiWlSolution *
206 giraffe_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 
441 void
442 giraffe_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 
464 const cxchar *
465 giraffe_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 
481 GiModel *
482 giraffe_wlsolution_model(const GiWlSolution *self)
483 {
484 
485  cx_assert(self != NULL);
486 
487  return self->model;
488 
489 }
490 
491 
492 cxint
493 giraffe_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 
509 cxbool
510 giraffe_wlsolution_get_subslits(const GiWlSolution *self)
511 {
512 
513  cx_assert(self != NULL);
514 
515  return self->subslits;
516 
517 }
518 
519 
520 cxint
521 giraffe_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 
556 GiWlResiduals *
557 giraffe_wlsolution_get_residuals(const GiWlSolution *self)
558 {
559 
560  cx_assert(self != NULL);
561 
562  return self->residuals;
563 
564 }
565 
566 
567 void
568 giraffe_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 
583 cxdouble
584 giraffe_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 
634 cxdouble
635 giraffe_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 
688 GiTable *
689 giraffe_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_propertylist * giraffe_image_get_properties(const GiImage *self)
Get the properties of an image.
Definition: giimage.c:282
cpl_image * giraffe_image_get(const GiImage *self)
Gets the image data.
Definition: giimage.c:218
cxint giraffe_table_set(GiTable *self, cpl_table *table)
Sets the table data.
Definition: gitable.c:456
cpl_propertylist * giraffe_table_get_properties(const GiTable *self)
Gets the table properties.
Definition: gitable.c:489
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
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.10.
Documentation copyright © 2002-2006 European Southern Observatory.
Generated on Thu Dec 15 2022 21:18:52 by doxygen 1.9.1 written by Dimitri van Heesch, © 1997-2004