GIRAFFE Pipeline Reference Manual

gimodels.c
1 /* $Id$
2  *
3  * This file is part of the GIRAFFE Pipeline
4  * Copyright (C) 2002-2006 European Southern Observatory
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 /*
22  * $Author$
23  * $Date$
24  * $Revision$
25  * $Name$
26  */
27 
28 #ifdef HAVE_CONFIG_H
29 # include <config.h>
30 #endif
31 
32 #include <math.h>
33 
34 #include <cxtypes.h>
35 #include <cxmemory.h>
36 #include <cxmessages.h>
37 #include <cxstrutils.h>
38 
39 #include "gimacros.h"
40 #include "gimodels.h"
41 
42 
43 static GiModelData _gimodels[];
44 
45 const GiModelData *const giraffe_models = _gimodels;
46 
47 
48 /*
49  * Optical model argument indices
50  */
51 
52 enum {
53  LMI_WLEN = 0,
54  LMI_XFIB = 1,
55  LMI_YFIB = 2
56 };
57 
58 
59 /*
60  * Optical model parameter indices
61  */
62 
63 enum {
64  LMP_NX = 0,
65  LMP_NY = 0,
66  LMP_PXSIZ = 1,
67  LMP_FCOLL = 2,
68  LMP_CFACT = 3,
69  LMP_THETA = 4,
70  LMP_ORDER = 5,
71  LMP_SPACE = 6,
72  LMP_SOFFX = 7,
73  LMP_SOFFY = 8,
74  LMP_SPHI = 9
75 };
76 
77 
78 /*
79  * Line model parameter indices
80  */
81 
82 enum {
83  LMP_AMPL = 0,
84  LMP_CENT = 1,
85  LMP_BACK = 2,
86  LMP_WID1 = 3,
87  LMP_WID2 = 4
88 };
89 
90 
91 
92 static const cxint DW_DEGREE = 3;
93 static const cxdouble DW_LOG001 = 2.302585093; /* -log(0.1) */
94 
95 
96 /*
97  * Utility function to calculate a weighted exponential
98  *
99  * DW_DEGREE
100  * exp( - | x - x0 | )
101  * w = -------------------------------
102  * / DW_DEGREE \
103  * | --------- |
104  * \ DW_LOG001 /
105  * dx
106  */
107 
108 inline static cxdouble
109 _giraffe_dydaweight(cxdouble x, cxdouble x0, cxdouble dx)
110 {
111 
112  register cxdouble w;
113 
114 
115  w = exp(-pow(fabs(x - x0), DW_DEGREE) / pow(dx, DW_DEGREE / DW_LOG001));
116 
117  if (isnan(w)) {
118  w = 1;
119  }
120 
121  return w;
122 
123 }
124 
125 
126 inline static void
127 _giraffe_model_dtor(GiModel *self)
128 {
129 
130  if (self->name) {
131  cx_free(self->name);
132  self->name = NULL;
133  }
134 
135 
136  self->arguments.count = 0;
137 
138  if (self->arguments.names) {
139  cpl_propertylist_delete(self->arguments.names);
140  self->arguments.names = NULL;
141  }
142 
143  if (self->arguments.values) {
144  cpl_matrix_delete(self->arguments.values);
145  self->arguments.values = NULL;
146  }
147 
148 
149  self->parameters.count = 0;
150 
151  if (self->parameters.names) {
152  cpl_propertylist_delete(self->parameters.names);
153  self->parameters.names = NULL;
154  }
155 
156  if (self->parameters.values) {
157  cpl_matrix_delete(self->parameters.values);
158  self->parameters.values = NULL;
159  }
160 
161  if (self->parameters.limits) {
162  cpl_matrix_delete(self->parameters.limits);
163  self->parameters.limits = NULL;
164  }
165 
166  if (self->parameters.flags) {
167  cx_free(self->parameters.flags);
168  self->parameters.flags = NULL;
169  }
170 
171 
172  self->fit.iterations = 0;
173 
174  if (self->fit.covariance) {
175  cpl_matrix_delete(self->fit.covariance);
176  self->fit.covariance = NULL;
177  }
178 
179  return;
180 
181 }
182 
183 
184 inline static void
185 _giraffe_xoptmod_ctor(GiModel *self, const GiModelData *model)
186 {
187 
188  cx_assert(self != NULL);
189  cx_assert(model != NULL);
190 
191  self->name = cx_strdup(model->name);
192  self->type = model->type;
193 
194  self->model = model->eval;
195 
196 
197  /*
198  * Arguments
199  */
200 
201  self->arguments.names = cpl_propertylist_new();
202 
203  cpl_propertylist_append_int(self->arguments.names, "xf", LMI_XFIB);
204  cpl_propertylist_append_int(self->arguments.names, "yf", LMI_YFIB);
205  cpl_propertylist_append_int(self->arguments.names, "lambda", LMI_WLEN);
206 
207  self->arguments.count = cpl_propertylist_get_size(self->arguments.names);
208  self->arguments.values = cpl_matrix_new(self->arguments.count, 1);
209 
210 
211  /*
212  * Parameters
213  */
214 
215  self->parameters.names = cpl_propertylist_new();
216 
217  cpl_propertylist_append_int(self->parameters.names, "Orientation",
218  LMP_NX);
219  cpl_propertylist_append_int(self->parameters.names, "Order",
220  LMP_ORDER);
221  cpl_propertylist_append_int(self->parameters.names, "PixelSize",
222  LMP_PXSIZ);
223  cpl_propertylist_append_int(self->parameters.names, "FocalLength",
224  LMP_FCOLL);
225  cpl_propertylist_append_int(self->parameters.names, "Magnification",
226  LMP_CFACT);
227  cpl_propertylist_append_int(self->parameters.names, "Angle",
228  LMP_THETA);
229  cpl_propertylist_append_int(self->parameters.names, "Spacing",
230  LMP_SPACE);
231 
232  self->parameters.count =
233  cpl_propertylist_get_size(self->parameters.names);
234  self->parameters.values = cpl_matrix_new(self->parameters.count, 1);
235 
236  return;
237 
238 }
239 
240 
241 inline static void
242 _giraffe_xoptmod_eval(cxdouble *y, cxdouble *x, cxdouble *a, cxint na,
243  cxdouble *dyda, cxdouble *r)
244 {
245 
246  const cxchar *const fctid = "_giraffe_xoptmod_eval";
247 
248 
249  cxdouble lambda;
250  cxdouble xfibre;
251  cxdouble yfibre;
252 
253  cxdouble pixsize, nx;
254  cxdouble fcoll, cfact;
255  cxdouble gtheta, gorder, gspace;
256 
257  register cxdouble xccd, d, X;
258  register cxdouble yfibre2, tmp, tmp2, d2, X2, gspace2;
259  register cxdouble sqtmp, costheta, sintheta;
260 
261 
262 
263  if (na != 7) {
264  cpl_error_set(fctid, CPL_ERROR_ILLEGAL_INPUT);
265  return;
266  }
267 
268  *y = 0.0;
269 
270  if (dyda != NULL) {
271  dyda[LMP_NX] = 0.;
272  dyda[LMP_PXSIZ] = 0.;
273  dyda[LMP_FCOLL] = 0.;
274  dyda[LMP_CFACT] = 0.;
275  dyda[LMP_THETA] = 0.;
276  dyda[LMP_ORDER] = 0.;
277  dyda[LMP_SPACE] = 0.;
278  }
279 
280  lambda = x[LMI_WLEN]; /* wavelength [nm] */
281  xfibre = x[LMI_XFIB]; /* X fibre [mm] */
282  yfibre = x[LMI_YFIB]; /* Y fibre [mm] */
283 
284  nx = a[LMP_NX]; /* CCD size along X [pixels] */
285  pixsize = a[LMP_PXSIZ]; /* CCD pixel size [mm] */
286  fcoll = a[LMP_FCOLL]; /* collimator focal length [mm] */
287  cfact = a[LMP_CFACT]; /* camera magnification factor */
288  gtheta = a[LMP_THETA]; /* grating angle [radian] */
289  gorder = a[LMP_ORDER]; /* grating diffraction order */
290  gspace = a[LMP_SPACE]; /* grating groove spacing [mm] */
291 
292 
293  lambda *= GI_NM_TO_MM; /* wavelength [mm] */
294 
295  yfibre2 = yfibre * yfibre;
296  gspace2 = gspace * gspace;
297  costheta = cos(gtheta);
298  sintheta = sin(gtheta);
299 
300  d2 = xfibre * xfibre + yfibre2 + (fcoll * fcoll);
301  d = sqrt(d2);
302 
303  X = (-lambda * gorder / gspace) + (xfibre * costheta / d) +
304  (fcoll * sintheta / d);
305  X2 = X * X;
306 
307  sqtmp = sqrt(1.0 - yfibre2 / d2 - X2);
308  tmp = -sintheta * X + costheta * sqtmp;
309  tmp2 = tmp * tmp;
310  xccd = (cfact * fcoll * (X * costheta + sintheta * sqtmp)) / tmp;
311 
312 
313  /*
314  * Take care of model direction
315  */
316 
317  if (nx < 0.0) {
318  *y = xccd / pixsize - 0.5 * nx;
319  }
320  else {
321  *y = -xccd / pixsize + 0.5 * nx;
322  }
323 
324 
325  /*
326  * If requested, compute the partial derivatives of y
327  * with respect to each parameter.
328  */
329 
330  if (dyda != NULL) {
331 
332  dyda[LMP_NX] = 0.5;
333  dyda[LMP_PXSIZ] = 0.0;
334 
335  dyda[LMP_FCOLL] = cfact * (costheta * X + sintheta * sqtmp) / tmp +
336  cfact * fcoll * (costheta * (-X * fcoll / d2 + sintheta / d -
337  gorder * lambda * fcoll /
338  (d2 * gspace)) + 0.5 * sintheta *
339  (-2.0 * X * (-X * fcoll / d2 + sintheta / d -
340  gorder * lambda * fcoll /
341  (d2 * gspace)) +
342  2.0 * yfibre2 * fcoll / (d2 * d2)) / sqtmp) /
343  tmp - cfact * fcoll * (costheta * X + sintheta * sqtmp) *
344  (-sintheta * (-X * fcoll / d2 + sintheta / d - gorder * lambda *
345  fcoll / (d2 * gspace)) + 0.5 * costheta *
346  (-2.0 * X * (-X * fcoll / d2 + sintheta / d - gorder * lambda *
347  fcoll / (d2 * gspace)) + 2.0 * yfibre2 * fcoll /
348  (d2 * d2)) / sqtmp) / tmp2;
349 
350  dyda[LMP_FCOLL] /= pixsize;
351  dyda[LMP_CFACT] = (xccd / cfact) / pixsize;
352 
353  dyda[LMP_THETA] = cfact * fcoll * ((-xfibre * sintheta / d + fcoll *
354  costheta / d) * costheta -
355  sintheta * X - sintheta * X *
356  (-xfibre * sintheta / d + fcoll *
357  costheta / d) / sqtmp +
358  costheta * sqtmp) / tmp -
359  cfact * fcoll * (costheta * X + sintheta * sqtmp) *
360  (-(-xfibre * sintheta / d + fcoll * costheta / d) * sintheta -
361  costheta * X - costheta * X * (-xfibre * sintheta / d + fcoll *
362  costheta / d) /
363  sqtmp - sintheta * sqtmp) / tmp2;
364 
365  dyda[LMP_THETA] /= pixsize;
366  dyda[LMP_ORDER] = 0.0;
367 
368  dyda[LMP_SPACE] = cfact * fcoll * (lambda * gorder * costheta /
369  gspace2 - sintheta * X * lambda *
370  gorder / (sqtmp * gspace2)) /
371  tmp - cfact * fcoll * (X * costheta + sintheta * sqtmp) *
372  (-lambda * gorder * sintheta / gspace2 - costheta * X * lambda *
373  gorder / (sqtmp * gspace2)) / tmp2;
374 
375  dyda[LMP_SPACE] /= pixsize;
376 
377  if (nx > 0.) {
378  dyda[LMP_NX] = -dyda[LMP_NX];
379  dyda[LMP_PXSIZ] = -dyda[LMP_PXSIZ];
380  dyda[LMP_FCOLL] = -dyda[LMP_FCOLL];
381  dyda[LMP_CFACT] = -dyda[LMP_CFACT];
382  dyda[LMP_THETA] = -dyda[LMP_THETA];
383  dyda[LMP_ORDER] = -dyda[LMP_ORDER];
384  dyda[LMP_SPACE] = -dyda[LMP_SPACE];
385  }
386 
387  if (r != NULL) {
388 
389  register cxint k;
390 
391  k = LMP_FCOLL << 1;
392  if (r[k+1] > 0) {
393  dyda[LMP_FCOLL] *= _giraffe_dydaweight(a[LMP_FCOLL], r[k],
394  r[k + 1]);
395  }
396 
397  k = LMP_CFACT << 1;
398  if (r[k+1] > 0) {
399  dyda[LMP_CFACT] *= _giraffe_dydaweight(a[LMP_CFACT], r[k],
400  r[k + 1]);
401  }
402 
403  k = LMP_THETA << 1;
404  if (r[k+1] > 0) {
405  dyda[LMP_THETA] *= _giraffe_dydaweight(a[LMP_THETA], r[k],
406  r[k + 1]);
407  }
408 
409  k = LMP_SPACE << 1;
410  if (r[k+1] > 0) {
411  dyda[LMP_SPACE] *= _giraffe_dydaweight(a[LMP_SPACE], r[k],
412  r[k + 1]);
413  }
414 
415  }
416 
417  }
418 
419  return;
420 
421 }
422 
423 
424 inline static void
425 _giraffe_yoptmod_ctor(GiModel *self, const GiModelData *model)
426 {
427 
428  cx_assert(self != NULL);
429  cx_assert(model != NULL);
430 
431  self->name = cx_strdup(model->name);
432  self->type = model->type;
433 
434  self->model = model->eval;
435 
436 
437  /*
438  * Arguments
439  */
440 
441  self->arguments.names = cpl_propertylist_new();
442 
443  cpl_propertylist_append_int(self->arguments.names, "xf", LMI_XFIB);
444  cpl_propertylist_append_int(self->arguments.names, "yf", LMI_YFIB);
445  cpl_propertylist_append_int(self->arguments.names, "lambda", LMI_WLEN);
446 
447  self->arguments.count = cpl_propertylist_get_size(self->arguments.names);
448  self->arguments.values = cpl_matrix_new(self->arguments.count, 1);
449 
450 
451  /*
452  * Parameters
453  */
454 
455  self->parameters.names = cpl_propertylist_new();
456 
457  cpl_propertylist_append_int(self->parameters.names, "Orientation",
458  LMP_NY);
459  cpl_propertylist_append_int(self->parameters.names, "Order",
460  LMP_ORDER);
461  cpl_propertylist_append_int(self->parameters.names, "PixelSize",
462  LMP_PXSIZ);
463  cpl_propertylist_append_int(self->parameters.names, "FocalLength",
464  LMP_FCOLL);
465  cpl_propertylist_append_int(self->parameters.names, "Magnification",
466  LMP_CFACT);
467  cpl_propertylist_append_int(self->parameters.names, "Angle",
468  LMP_THETA);
469  cpl_propertylist_append_int(self->parameters.names, "Spacing",
470  LMP_SPACE);
471 
472  self->parameters.count =
473  cpl_propertylist_get_size(self->parameters.names);
474  self->parameters.values = cpl_matrix_new(self->parameters.count, 1);
475 
476  return;
477 
478 }
479 
480 
481 inline static void
482 _giraffe_yoptmod_eval(cxdouble *y, cxdouble *x, cxdouble *a, cxint na,
483  cxdouble *dyda, cxdouble *r)
484 {
485 
486  const cxchar *const fctid = "_giraffe_yoptmod_eval";
487 
488  cxdouble lambda, xfibre, yfibre;
489  cxdouble pixsize, ny;
490  cxdouble fcoll,cfact;
491  cxdouble gtheta,gorder,gspace;
492 
493  register cxdouble t2, t3, t4, t5, t6, t7, t8, t9;
494  register cxdouble t10, t12, t13, t15, t18;
495  register cxdouble t22, t24, t26, t27, t28, t29;
496  register cxdouble t30, t33;
497  register cxdouble t41, t45, t47;
498  register cxdouble t53, t56, t57;
499  register cxdouble t76;
500  register cxdouble t93, t94;
501 
502 
503  /* Not used */
504  (void) r;
505 
506  if (na != 7) {
507  cpl_error_set(fctid, CPL_ERROR_ILLEGAL_INPUT);
508  return;
509  }
510 
511  *y = 0.;
512 
513  if (dyda != NULL) {
514  dyda[LMP_NY] = 0.;
515  dyda[LMP_PXSIZ] = 0.;
516  dyda[LMP_FCOLL] = 0.;
517  dyda[LMP_CFACT] = 0.;
518  dyda[LMP_THETA] = 0.;
519  dyda[LMP_ORDER] = 0.;
520  dyda[LMP_SPACE] = 0.;
521  }
522 
523  lambda = x[LMI_WLEN];
524  xfibre = x[LMI_XFIB];
525  yfibre = x[LMI_YFIB];
526 
527  ny = a[LMP_NY];
528  pixsize = a[LMP_PXSIZ];
529  fcoll = a[LMP_FCOLL];
530  cfact = a[LMP_CFACT];
531  gtheta = a[LMP_THETA];
532  gorder = a[LMP_ORDER];
533  gspace = a[LMP_SPACE];
534 
535  lambda *= GI_NM_TO_MM;
536 
537  t2 = cfact * fcoll * yfibre;
538  t3 = xfibre * xfibre;
539  t4 = yfibre * yfibre;
540  t5 = fcoll * fcoll;
541  t6 = t3 + t4 + t5;
542  t7 = sqrt(t6);
543  t8 = 1.0 / t7;
544  t9 = lambda * gorder;
545  t10 = 1.0 / gspace;
546  t12 = cos(gtheta);
547  t13 = xfibre * t12;
548  t15 = sin(gtheta);
549  t18 = -t9 * t10 + t13 * t8 + fcoll * t15 * t8;
550  t22 = t18 * t18;
551  t24 = sqrt(1.0 - t4 / t6 - t22);
552  t26 = -t18 * t15 + t12 * t24;
553  t27 = 1.0 / t26;
554  t28 = t8 * t27;
555  t29 = 1.0 / pixsize;
556  t30 = t28 * t29;
557  t33 = pixsize * pixsize;
558  t41 = 1.0 / t7 / t6;
559  t45 = t26 * t26;
560  t47 = t8 / t45;
561  t53 = -t13 * t41 * fcoll + t15 * t8 - t5 * t15 * t41;
562  t56 = t12 / t24;
563  t57 = t6 * t6;
564  t76 = -xfibre * t15 * t8 + fcoll * t12 * t8;
565  t93 = gspace * gspace;
566  t94 = 1.0 / t93;
567 
568  *y = -t2 * t30 + 0.5 * ny;
569 
570 
571  /*
572  * If requested, compute the partial derivatives of y
573  * with respect to each parameter.
574  */
575 
576  if (dyda != NULL) {
577 
578  dyda[LMP_NY] = 0.5;
579  dyda[LMP_PXSIZ] = t2 * t28 / t33;
580  dyda[LMP_FCOLL] = -cfact * yfibre * t30 + cfact * t5 *
581  yfibre * t41 * t27 * t29 + t2 * t47 * t29 *
582  (-t53 * t15 + t56 * (2.0 * t4 / t57 * fcoll -
583  2.0 * t18 * t53) / 2.0);
584  dyda[LMP_CFACT] = -fcoll * yfibre * t30;
585  dyda[LMP_THETA] = t2 * t47 * t29 * (-t76 * t15 - t18 * t12 -
586  t15 * t24 - t56 * t18 * t76);
587  dyda[LMP_ORDER] = t2 * t47 *t29 *(lambda * t10 * t15 + t56 *
588  t18 * lambda * t10);
589  dyda[LMP_SPACE] = t2 * t47 * t29 * (-t9 * t94 * t15 -
590  t56 * t18 * t9 * t94);
591 
592  }
593 
594  return;
595 
596 }
597 
598 
599 inline static void
600 _giraffe_xoptmod2_ctor(GiModel *self, const GiModelData *model)
601 {
602 
603  cx_assert(self != NULL);
604  cx_assert(model != NULL);
605 
606  self->name = cx_strdup(model->name);
607  self->type = model->type;
608 
609  self->model = model->eval;
610 
611 
612  /*
613  * Arguments
614  */
615 
616  self->arguments.names = cpl_propertylist_new();
617 
618  cpl_propertylist_append_int(self->arguments.names, "xf", LMI_XFIB);
619  cpl_propertylist_append_int(self->arguments.names, "yf", LMI_YFIB);
620  cpl_propertylist_append_int(self->arguments.names, "lambda", LMI_WLEN);
621 
622  self->arguments.count = cpl_propertylist_get_size(self->arguments.names);
623  self->arguments.values = cpl_matrix_new(self->arguments.count, 1);
624 
625 
626  /*
627  * Parameters
628  */
629 
630  self->parameters.names = cpl_propertylist_new();
631 
632  cpl_propertylist_append_int(self->parameters.names, "Orientation",
633  LMP_NX);
634  cpl_propertylist_append_int(self->parameters.names, "Order",
635  LMP_ORDER);
636  cpl_propertylist_append_int(self->parameters.names, "PixelSize",
637  LMP_PXSIZ);
638  cpl_propertylist_append_int(self->parameters.names, "FocalLength",
639  LMP_FCOLL);
640  cpl_propertylist_append_int(self->parameters.names, "Magnification",
641  LMP_CFACT);
642  cpl_propertylist_append_int(self->parameters.names, "Angle",
643  LMP_THETA);
644  cpl_propertylist_append_int(self->parameters.names, "Spacing",
645  LMP_SPACE);
646  cpl_propertylist_append_int(self->parameters.names, "Sdx",
647  LMP_SOFFX);
648  cpl_propertylist_append_int(self->parameters.names, "Sdy",
649  LMP_SOFFY);
650  cpl_propertylist_append_int(self->parameters.names, "Sphi",
651  LMP_SPHI);
652 
653  self->parameters.count =
654  cpl_propertylist_get_size(self->parameters.names);
655  self->parameters.values = cpl_matrix_new(self->parameters.count, 1);
656 
657  return;
658 
659 }
660 
661 
662 inline static void
663 _giraffe_xoptmod2_eval(cxdouble *y, cxdouble *x, cxdouble *a, cxint na,
664  cxdouble *dyda, cxdouble *r)
665 {
666 
667  const cxchar *const fctid = "_giraffe_xoptmod2_eval";
668 
669 
670  cxdouble lambda;
671  cxdouble xfibre;
672  cxdouble yfibre;
673 
674  cxdouble pixsize, nx;
675  cxdouble fcoll, cfact;
676  cxdouble gtheta, gorder, gspace;
677  cxdouble slitdx, slitdy, slitphi;
678 
679  register cxdouble t1, t2, t3, t4, t9;
680  register cxdouble t10, t11, t12, t14, t16, t17, t18, t19;
681  register cxdouble t20, t21, t23, t24, t26, t27, t28;
682  register cxdouble t30, t32, t33, t34, t35, t36, t37, t38, t39;
683  register cxdouble t40, t44, t49;
684  register cxdouble t52, t58;
685  register cxdouble t60, t61, t62, t64, t68;
686  register cxdouble t75, t76, t78;
687  register cxdouble t80;
688  register cxdouble t91, t93;
689  register cxdouble t104, t107;
690  register cxdouble t113, t119;
691  register cxdouble t120, t121, t124;
692  register cxdouble t136, t137, t138;
693  register cxdouble t143, t148;
694  register cxdouble t161, t162, t166, t168;
695  register cxdouble t173;
696  register cxdouble t191, t195, t196;
697  register cxdouble t201, t210;
698 
699 
700  if (na != 10) {
701  cpl_error_set(fctid, CPL_ERROR_ILLEGAL_INPUT);
702  return;
703  }
704 
705  *y = 0.0;
706 
707  if (dyda != NULL) {
708  dyda[LMP_NX] = 0.;
709  dyda[LMP_PXSIZ] = 0.;
710  dyda[LMP_FCOLL] = 0.;
711  dyda[LMP_CFACT] = 0.;
712  dyda[LMP_THETA] = 0.;
713  dyda[LMP_ORDER] = 0.;
714  dyda[LMP_SPACE] = 0.;
715  dyda[LMP_SOFFX] = 0.;
716  dyda[LMP_SOFFY] = 0.;
717  dyda[LMP_SPHI] = 0.;
718  }
719 
720  lambda = x[LMI_WLEN]; /* wavelength [nm] */
721  xfibre = x[LMI_XFIB]; /* Y fibre [mm] */
722  yfibre = x[LMI_YFIB]; /* Y fibre [mm] */
723 
724  nx = a[LMP_NX]; /* CCD size in X [pixels] */
725  pixsize = a[LMP_PXSIZ]; /* CCD pixel size [mm] */
726  fcoll = a[LMP_FCOLL]; /* collimator focal length [mm] */
727  cfact = a[LMP_CFACT]; /* camera magnification factor */
728  gtheta = a[LMP_THETA]; /* grating angle [radian] */
729  gorder = a[LMP_ORDER]; /* grating diffraction order */
730  gspace = a[LMP_SPACE]; /* grating groove spacing [mm] */
731  slitdx = a[LMP_SOFFX]; /* slit position x offset [mm] */
732  slitdy = a[LMP_SOFFY]; /* slit position y offset [mm] */
733  slitphi = a[LMP_SPHI]; /* slit position angle [radian] */
734 
735  lambda *= GI_NM_TO_MM; /* wavelength [mm] */
736 
737  t1 = cfact * fcoll;
738  t2 = cos(gtheta);
739  t3 = lambda * gorder;
740  t4 = 1.0 / gspace;
741  t9 = xfibre * (1.0 + slitphi * yfibre) + slitdx;
742  t10 = t9 * t2;
743  t11 = t9 * t9;
744  t12 = slitphi * slitphi;
745  t14 = sqrt(1.0 - t12);
746  t16 = yfibre * t14 + slitdy;
747  t17 = t16 * t16;
748  t18 = fcoll * fcoll;
749  t19 = t11 + t17 + t18;
750  t20 = sqrt(t19);
751  t21 = 1.0 / t20;
752  t23 = sin(gtheta);
753  t24 = fcoll * t23;
754  t26 = -t3 * t4 + t10 * t21 + t24 * t21;
755  t27 = t2 * t26;
756  t28 = 1.0 / t19;
757  t30 = t26 * t26;
758  t32 = sqrt(1.0 - t17 * t28 - t30);
759  t33 = t23 * t32;
760  t34 = t27 + t33;
761  t35 = t23 * t26;
762  t36 = t2 * t32;
763  t37 = -t35 + t36;
764  t38 = 1.0 / t37;
765  t39 = t34 * t38;
766  t40 = 1.0 / pixsize;
767  t44 = pixsize * pixsize;
768  t49 = t38 * t40;
769  t52 = 1.0 / t20 / t19;
770  t58 = -t10 * t52 * fcoll + t23 * t21 - t18 * t23 * t52;
771  t60 = 1.0 / t32;
772  t61 = t23 * t60;
773  t62 = t19 * t19;
774  t64 = t17 / t62;
775  t68 = 2.0 * t64 * fcoll - 2.0 * t26 * t58;
776  t75 = t1 * t34;
777  t76 = t37 * t37;
778  t78 = 1.0 / t76 * t40;
779  t80 = t2 * t60;
780  t91 = -t9 * t23 * t21 + fcoll * t2 * t21;
781  t93 = t26 * t91;
782  t104 = t2 * lambda;
783  t107 = t26 * lambda * t4;
784  t113 = t23 * lambda;
785  t119 = gspace * gspace;
786  t120 = 1.0 / t119;
787  t121 = gorder * t120;
788  t124 = t3 * t120;
789  t136 = t2 * t21;
790  t137 = 2.0 * t9;
791  t138 = t52 * t137;
792  t143 = t136 - t10 * t138 / 2.0 - t24 * t138 / 2.0;
793  t148 = t64 * t137 - 2.0 * t26 * t143;
794  t161 = 2.0 * t16;
795  t162 = t52 * t161;
796  t166 = -t10 * t162 / 2.0 - t24 * t162 / 2.0;
797  t168 = t16 * t28;
798  t173 = -2.0 * t168 + t64 * t161 - 2.0 * t26 * t166;
799  t191 = 1.0 / t14;
800  t195 = 2.0 * t9 * xfibre * yfibre - 2.0 * t16 * yfibre * t191 * slitphi;
801  t196 = t52 * t195;
802  t201 = xfibre * yfibre * t136 - t10 * t196 / 2.0 - t24 * t196 / 2.0;
803  t210 = 2.0 * t168 * yfibre * t191 * slitphi + t64 * t195 -
804  2.0 * t26 * t201;
805 
806 
807  /*
808  * Take care of model direction
809  */
810 
811  if (nx < 0.0) {
812  *y = t1 * t39 * t40 - 0.5 * nx;
813  }
814  else {
815  *y = -t1 * t39 * t40 + 0.5 * nx;
816  }
817 
818 
819  /*
820  * If requested, compute the partial derivatives of y
821  * with respect to each parameter.
822  */
823 
824  if (dyda != NULL) {
825 
826  dyda[LMP_NX] = 0.5;
827  dyda[LMP_PXSIZ] = -t1 * t39 / t44;
828  dyda[LMP_FCOLL] = cfact * t34 * t49 + t1 *
829  (t2 * t58 + t61 * t68 / 2.0) * t38 * t40 -
830  t75 * t78 * (-t23 * t58 + t80 * t68 / 2.0);
831  dyda[LMP_CFACT] = fcoll * t34 * t49;
832  dyda[LMP_THETA] = t1 * (-t35 + t2 * t91 + t36 - t61 * t93) * t38 *
833  t40 - t75 * t78 * (-t27 - t23 * t91 - t33 - t80 * t93);
834  dyda[LMP_ORDER] = t1 * (-t104 * t4 + t61 * t107) * t38 * t40 - t75 *
835  t78 * (t113 * t4 + t80 * t107);
836  dyda[LMP_SPACE] = t1 * (t104 * t121 - t61 * t26 * t124) * t38 * t40 -
837  t75 * t78 * (-t113 * t121 - t80 * t26 * t124);
838  dyda[LMP_SOFFX] = t1 * (t2 * t143 + t61 * t148 / 2.0) * t38 * t40 -
839  t75 * t78 * (-t23 * t143 + t80 * t148 / 2.0);
840  dyda[LMP_SOFFY] = t1 * (t2 * t166 + t61 * t173 / 2.0) * t38 * t40 -
841  t75 * t78 * (-t23 * t166 + t80 * t173 / 2.0);
842  dyda[LMP_SPHI] = t1 * (t2 * t201 + t61 * t210 / 2.0) * t38 * t40 -
843  t75 * t78 * (-t23 * t201 + t80 * t210 / 2.0);
844 
845  if (nx > 0.0) {
846  dyda[LMP_NX] = -dyda[LMP_NX];
847  dyda[LMP_PXSIZ] = -dyda[LMP_PXSIZ];
848  dyda[LMP_FCOLL] = -dyda[LMP_FCOLL];
849  dyda[LMP_CFACT] = -dyda[LMP_CFACT];
850  dyda[LMP_THETA] = -dyda[LMP_THETA];
851  dyda[LMP_ORDER] = -dyda[LMP_ORDER];
852  dyda[LMP_SPACE] = -dyda[LMP_SPACE];
853  dyda[LMP_SOFFX] = -dyda[LMP_SOFFX];
854  dyda[LMP_SOFFY] = -dyda[LMP_SOFFY];
855  dyda[LMP_SPHI] = -dyda[LMP_SPHI];
856  }
857 
858  if (r != NULL) {
859 
860  register cxint k;
861 
862 
863  k = LMP_PXSIZ << 1;
864  if (r[k + 1] > 0) {
865  dyda[LMP_PXSIZ] *= _giraffe_dydaweight(a[LMP_PXSIZ], r[k],
866  r[k + 1]);
867  }
868 
869  k = LMP_FCOLL << 1;
870  if (r[k + 1] > 0) {
871  dyda[LMP_FCOLL] *= _giraffe_dydaweight(a[LMP_FCOLL], r[k],
872  r[k + 1]);
873  }
874 
875  k = LMP_CFACT << 1;
876  if (r[k + 1] > 0) {
877  dyda[LMP_CFACT] *= _giraffe_dydaweight(a[LMP_CFACT], r[k],
878  r[k + 1]);
879  }
880 
881  k = LMP_THETA << 1;
882  if (r[k + 1] > 0) {
883  dyda[LMP_THETA] *= _giraffe_dydaweight(a[LMP_THETA], r[k],
884  r[k + 1]);
885  }
886 
887  k = LMP_ORDER << 1;
888  if (r[k + 1] > 0) {
889  dyda[LMP_ORDER] *= _giraffe_dydaweight(a[LMP_ORDER], r[k],
890  r[k + 1]);
891  }
892 
893  k = LMP_SPACE << 1;
894  if (r[k + 1] > 0) {
895  dyda[LMP_SPACE] *= _giraffe_dydaweight(a[LMP_SPACE], r[k],
896  r[k + 1]);
897  }
898 
899  k = LMP_SOFFX << 1;
900  if (r[k + 1] > 0) {
901  dyda[LMP_SOFFX] *= _giraffe_dydaweight(a[LMP_SOFFX], r[k],
902  r[k + 1]);
903  }
904 
905  k = LMP_SOFFY << 1;
906  if (r[k + 1] > 0) {
907  dyda[LMP_SOFFY] *= _giraffe_dydaweight(a[LMP_SOFFY], r[k],
908  r[k + 1]);
909  }
910 
911  k = LMP_SPHI << 1;
912  if (r[k + 1] > 0) {
913  dyda[LMP_SPHI] *= _giraffe_dydaweight(a[LMP_SPHI], r[k],
914  r[k + 1]);
915  }
916 
917  }
918 
919  }
920 
921  return;
922 
923 }
924 
925 
926 inline static void
927 _giraffe_yoptmod2_ctor(GiModel *self, const GiModelData *model)
928 {
929 
930  cx_assert(self != NULL);
931  cx_assert(model != NULL);
932 
933  self->name = cx_strdup(model->name);
934  self->type = model->type;
935 
936  self->model = model->eval;
937 
938 
939  /*
940  * Arguments
941  */
942 
943  self->arguments.names = cpl_propertylist_new();
944 
945  cpl_propertylist_append_int(self->arguments.names, "xf", LMI_XFIB);
946  cpl_propertylist_append_int(self->arguments.names, "yf", LMI_YFIB);
947  cpl_propertylist_append_int(self->arguments.names, "lambda", LMI_WLEN);
948 
949  self->arguments.count = cpl_propertylist_get_size(self->arguments.names);
950  self->arguments.values = cpl_matrix_new(self->arguments.count, 1);
951 
952 
953  /*
954  * Parameters
955  */
956 
957  self->parameters.names = cpl_propertylist_new();
958 
959  cpl_propertylist_append_int(self->parameters.names, "Orientation",
960  LMP_NY);
961  cpl_propertylist_append_int(self->parameters.names, "Order",
962  LMP_ORDER);
963  cpl_propertylist_append_int(self->parameters.names, "PixelSize",
964  LMP_PXSIZ);
965  cpl_propertylist_append_int(self->parameters.names, "FocalLength",
966  LMP_FCOLL);
967  cpl_propertylist_append_int(self->parameters.names, "Magnification",
968  LMP_CFACT);
969  cpl_propertylist_append_int(self->parameters.names, "Angle",
970  LMP_THETA);
971  cpl_propertylist_append_int(self->parameters.names, "Spacing",
972  LMP_SPACE);
973  cpl_propertylist_append_int(self->parameters.names, "Sdx",
974  LMP_SOFFX);
975  cpl_propertylist_append_int(self->parameters.names, "Sdy",
976  LMP_SOFFY);
977  cpl_propertylist_append_int(self->parameters.names, "Sphi",
978  LMP_SPHI);
979 
980  self->parameters.count =
981  cpl_propertylist_get_size(self->parameters.names);
982  self->parameters.values = cpl_matrix_new(self->parameters.count, 1);
983 
984  return;
985 
986 }
987 
988 
989 inline static void
990 _giraffe_yoptmod2_eval(cxdouble *y, cxdouble *x, cxdouble *a, cxint na,
991  cxdouble *dyda, cxdouble *r)
992 {
993 
994  const cxchar *const fctid = "_giraffe_yoptmod2_eval";
995 
996 
997  cxdouble lambda, xfibre, yfibre;
998  cxdouble pixsize, ny;
999  cxdouble fcoll, cfact;
1000  cxdouble gtheta, gorder, gspace;
1001  cxdouble slitdx, slitdy, slitphi;
1002 
1003  register cxdouble t1, t2, t4, t6, t7;
1004  register cxdouble t11, t12, t13, t14, t15, t16, t17, t18, t19;
1005  register cxdouble t21, t22, t24, t25, t27, t29;
1006  register cxdouble t31, t33, t35, t36, t37, t38, t39;
1007  register cxdouble t42, t50, t51, t54, t56;
1008  register cxdouble t62, t65, t66, t68;
1009  register cxdouble t85;
1010  register cxdouble t102, t103;
1011  register cxdouble t112, t117, t118;
1012  register cxdouble t123;
1013  register cxdouble t136;
1014  register cxdouble t141, t145, t147;
1015  register cxdouble t159;
1016  register cxdouble t160;
1017  register cxdouble t172, t179;
1018  register cxdouble t184;
1019 
1020 
1021  /* Not used */
1022  (void) r;
1023 
1024  if (na != 10) {
1025  cpl_error_set(fctid, CPL_ERROR_ILLEGAL_INPUT);
1026  return;
1027  }
1028 
1029  *y = 0.0;
1030 
1031  if (dyda != NULL) {
1032  dyda[LMP_NY] = 0.;
1033  dyda[LMP_PXSIZ] = 0.;
1034  dyda[LMP_FCOLL] = 0.;
1035  dyda[LMP_CFACT] = 0.;
1036  dyda[LMP_THETA] = 0.;
1037  dyda[LMP_ORDER] = 0.;
1038  dyda[LMP_SPACE] = 0.;
1039  dyda[LMP_SOFFX] = 0.;
1040  dyda[LMP_SOFFY] = 0.;
1041  dyda[LMP_SPHI] = 0.;
1042  }
1043 
1044  lambda = x[LMI_WLEN];
1045  xfibre = x[LMI_XFIB];
1046  yfibre = x[LMI_YFIB];
1047 
1048  ny = a[LMP_NY];
1049  pixsize = a[LMP_PXSIZ];
1050  fcoll = a[LMP_FCOLL];
1051  cfact = a[LMP_CFACT];
1052  gtheta = a[LMP_THETA];
1053  gorder = a[LMP_ORDER];
1054  gspace = a[LMP_SPACE];
1055  slitdx = a[LMP_SOFFX];
1056  slitdy = a[LMP_SOFFY];
1057  slitphi = a[LMP_SPHI];
1058 
1059  lambda *= GI_NM_TO_MM;
1060 
1061  t1 = cfact * fcoll;
1062  t2 = slitphi * slitphi;
1063  t4 = sqrt(1.0 - t2);
1064  t6 = yfibre * t4 + slitdy;
1065  t7 = t1 * t6;
1066  t11 = xfibre * (1.0 + slitphi * yfibre) + slitdx;
1067  t12 = t11 * t11;
1068  t13 = t6 * t6;
1069  t14 = fcoll * fcoll;
1070  t15 = t12 + t13 + t14;
1071  t16 = sqrt(t15);
1072  t17 = 1 / t16;
1073  t18 = lambda * gorder;
1074  t19 = 1 / gspace;
1075  t21 = cos(gtheta);
1076  t22 = t11 * t21;
1077  t24 = sin(gtheta);
1078  t25 = fcoll * t24;
1079  t27 = -t18 * t19 + t22 * t17 + t25 * t17;
1080  t29 = 1 / t15;
1081  t31 = t27 * t27;
1082  t33 = sqrt(1.0 - t13 * t29 - t31);
1083  t35 = -t27 * t24 + t21 * t33;
1084  t36 = 1 / t35;
1085  t37 = t17 * t36;
1086  t38 = 1 / pixsize;
1087  t39 = t37 * t38;
1088  t42 = pixsize * pixsize;
1089  t50 = 1 / t16 / t15;
1090  t51 = t50 * t36;
1091  t54 = t35 * t35;
1092  t56 = t17 / t54;
1093  t62 = -t22 * t50 * fcoll + t24 * t17 - t14 * t24 * t50;
1094  t65 = t21 / t33;
1095  t66 = t15 * t15;
1096  t68 = t13 / t66;
1097  t85 = -t11 * t24 * t17 + fcoll * t21 * t17;
1098  t102 = gspace * gspace;
1099  t103 = 1 / t102;
1100  t112 = 2.0 * t11;
1101  t117 = t21 * t17;
1102  t118 = t50 * t112;
1103  t123 = t117 - t22 * t118 / 2.0 - t25 * t118 / 2.0;
1104  t136 = 2.0 * t6;
1105  t141 = t50 * t136;
1106  t145 = -t22 * t141 / 2.0 - t25 * t141 / 2.0;
1107  t147 = t6 * t29;
1108  t159 = 1 / t4;
1109  t160 = yfibre * t159;
1110  t172 = 2.0 * t11 * xfibre * yfibre - 2.0 * t6 * yfibre * t159 * slitphi;
1111  t179 = t50 * t172;
1112  t184 = xfibre * yfibre * t117 - t22 * t179 / 2.0 - t25 * t179 / 2.0;
1113 
1114  *y = -t7 * t39 + 0.5 * ny;
1115 
1116  if (dyda != NULL) {
1117 
1118  dyda[LMP_NY] = 0.5;
1119  dyda[LMP_PXSIZ] = t7 * t37 / t42;
1120  dyda[LMP_FCOLL] = -cfact * t6 * t39 + cfact * t14 * t6 * t51 * t38 +
1121  t7 * t56 * t38 * (-t62 * t24 + t65 * (2.0 * t68 * fcoll -
1122  2.0 * t27 * t62) / 2.0);
1123  dyda[LMP_CFACT] = -fcoll * t6 * t39;
1124  dyda[LMP_THETA] = t7 * t56 * t38 * (-t85 * t24 - t27 * t21 - t24 *
1125  t33 - t65 * t27 * t85);
1126  dyda[LMP_ORDER] = t7 * t56 * t38 * (lambda * t19 * t24 + t65 * t27 *
1127  lambda * t19);
1128  dyda[LMP_SPACE] = t7 * t56 * t38 * (-t18 * t103 * t24 - t65 * t27 *
1129  t18 * t103);
1130  dyda[LMP_SOFFX] = t7 * t51 * t38 * t112 / 2.0 + t7 * t56 * t38 *
1131  (-t123 * t24 + t65 * (t68 * t112 - 2.0 * t27 * t123) / 2.0);
1132  dyda[LMP_SOFFY] = -t1 * t39 + t7 * t51 * t38 * t136 / 2.0 + t7 *
1133  t56 * t38 * (-t145 * t24 + t65 * (-2.0 * t147 + t68 * t136 -
1134  2.0 * t27 * t145) / 2.0);
1135  dyda[LMP_SPHI] = t1 * t160 * slitphi * t17 * t36 * t38 + t7 * t51 *
1136  t38 * t172 / 2.0 + t7 * t56 * t38 *
1137  (-t184 * t24 + t65 * (2.0 * t147 * t160 * slitphi + t68 * t172 -
1138  2.0 * t27 * t184) / 2.0);
1139 
1140  }
1141 
1142  return;
1143 
1144 }
1145 
1146 
1147 inline static void
1148 _giraffe_gaussian_ctor(GiModel *self, const GiModelData *model)
1149 {
1150 
1151  cx_assert(self != NULL);
1152  cx_assert(model != NULL);
1153 
1154  self->name = cx_strdup(model->name);
1155  self->type = model->type;
1156 
1157  self->model = model->eval;
1158 
1159 
1160  /*
1161  * Arguments
1162  */
1163 
1164  self->arguments.names = cpl_propertylist_new();
1165 
1166  cpl_propertylist_append_int(self->arguments.names, "x", 0);
1167 
1168  self->arguments.count = cpl_propertylist_get_size(self->arguments.names);
1169  self->arguments.values = cpl_matrix_new(self->arguments.count, 1);
1170 
1171 
1172  /*
1173  * Parameters
1174  */
1175 
1176  self->parameters.names = cpl_propertylist_new();
1177 
1178  cpl_propertylist_append_int(self->parameters.names, "Amplitude",
1179  LMP_AMPL);
1180  cpl_propertylist_append_int(self->parameters.names, "Center",
1181  LMP_CENT);
1182  cpl_propertylist_append_int(self->parameters.names, "Background",
1183  LMP_BACK);
1184  cpl_propertylist_append_int(self->parameters.names, "Width1",
1185  LMP_WID1);
1186 
1187  self->parameters.count =
1188  cpl_propertylist_get_size(self->parameters.names);
1189  self->parameters.values = cpl_matrix_new(self->parameters.count, 1);
1190 
1191  return;
1192 
1193 }
1194 
1195 
1196 inline static void
1197 _giraffe_gaussian_eval(cxdouble *y, cxdouble *x, cxdouble *a, cxint na,
1198  cxdouble *dyda, cxdouble *r)
1199 {
1200 
1201  const cxchar *const fctid = "_giraffe_gaussian_eval";
1202 
1203 
1204  cxdouble fac;
1205  cxdouble ex;
1206  cxdouble amplitude;
1207  cxdouble center;
1208  cxdouble backg;
1209  cxdouble width;
1210  cxdouble xred;
1211 
1212 
1213  /* Not used */
1214  (void) r;
1215 
1216  if (na != 4) {
1217  cpl_error_set(fctid, CPL_ERROR_ILLEGAL_INPUT);
1218  return;
1219  }
1220 
1221  *y = 0.0;
1222 
1223  if (dyda != NULL) {
1224  dyda[LMP_AMPL] = 0.;
1225  dyda[LMP_CENT] = 0.;
1226  dyda[LMP_BACK] = 0.;
1227  dyda[LMP_WID1] = 0.;
1228  }
1229 
1230 
1231  amplitude = a[LMP_AMPL];
1232  center = a[LMP_CENT];
1233  backg = a[LMP_BACK];
1234  width = a[LMP_WID1];
1235 
1236  xred = (x[0] - center) / width;
1237 
1238  ex = exp(-xred * xred / 2.);
1239  fac = amplitude * xred * ex;
1240 
1241  *y = amplitude * ex + backg;
1242 
1243 
1244  /*
1245  * If requested, compute the partial derivatives of y
1246  * with respect to each parameter.
1247  */
1248 
1249  if (dyda != NULL) {
1250 
1251  dyda[LMP_AMPL] = ex; /* d(y)/d(amplitude) */
1252  dyda[LMP_CENT] = fac / width; /* d(y)/d(center) */
1253  dyda[LMP_BACK] = 1.; /* d(y)/d(backg) */
1254  dyda[LMP_WID1] = (fac * xred) / width; /* d(y)/d(width) */
1255 
1256  }
1257 
1258  return;
1259 
1260 }
1261 
1262 
1263 inline static void
1264 _giraffe_psfcos_ctor(GiModel *self, const GiModelData *model)
1265 {
1266 
1267  cx_assert(self != NULL);
1268  cx_assert(model != NULL);
1269 
1270  self->name = cx_strdup(model->name);
1271  self->type = model->type;
1272 
1273  self->model = model->eval;
1274 
1275 
1276  /*
1277  * Arguments
1278  */
1279 
1280  self->arguments.names = cpl_propertylist_new();
1281 
1282  cpl_propertylist_append_int(self->arguments.names, "x", 0);
1283 
1284  self->arguments.count = cpl_propertylist_get_size(self->arguments.names);
1285  self->arguments.values = cpl_matrix_new(self->arguments.count, 1);
1286 
1287 
1288  /*
1289  * Parameters
1290  */
1291 
1292  self->parameters.names = cpl_propertylist_new();
1293 
1294  cpl_propertylist_append_int(self->parameters.names, "Amplitude",
1295  LMP_AMPL);
1296  cpl_propertylist_append_int(self->parameters.names, "Center",
1297  LMP_CENT);
1298  cpl_propertylist_append_int(self->parameters.names, "Background",
1299  LMP_BACK);
1300  cpl_propertylist_append_int(self->parameters.names, "Width1",
1301  LMP_WID1);
1302  cpl_propertylist_append_int(self->parameters.names, "Width2",
1303  LMP_WID2);
1304 
1305  self->parameters.count =
1306  cpl_propertylist_get_size(self->parameters.names);
1307  self->parameters.values = cpl_matrix_new(self->parameters.count, 1);
1308 
1309  return;
1310 
1311 }
1312 
1313 
1314 inline static void
1315 _giraffe_psfcos_eval(cxdouble *y, cxdouble *x, cxdouble *a, cxint na,
1316  cxdouble *dyda, cxdouble *r)
1317 {
1318 
1319  const cxchar *const fctid = "_giraffe_psfcos_eval";
1320 
1321 
1322  cxdouble amplitude;
1323  cxdouble center;
1324  cxdouble background;
1325  cxdouble width1;
1326  cxdouble width2;
1327 
1328  cxdouble t1, t2, t3, t4, t5, t6, t7, t8, t9;
1329  cxdouble t10, t13, t14, t15, t16;
1330  cxdouble t26;
1331 
1332 
1333  /* Not used */
1334  (void) r;
1335 
1336  if (na != 5) {
1337  cpl_error_set(fctid, CPL_ERROR_ILLEGAL_INPUT);
1338  return;
1339  }
1340 
1341  *y = 0.0;
1342 
1343  if (dyda != NULL) {
1344  dyda[LMP_AMPL] = 0.;
1345  dyda[LMP_CENT] = 0.;
1346  dyda[LMP_BACK] = 0.;
1347  dyda[LMP_WID1] = 0.;
1348  dyda[LMP_WID2] = 0.;
1349  }
1350 
1351  amplitude = a[LMP_AMPL];
1352  center = a[LMP_CENT];
1353  background = a[LMP_BACK];
1354  width1 = a[LMP_WID1];
1355  width2 = a[LMP_WID2];
1356 
1357  t1 = x[0] - center;
1358  t2 = fabs(t1);
1359  t3 = 1.0 / width2;
1360  t4 = t2 * t3;
1361  t5 = pow(t4, width1);
1362  t6 = CX_PI * t5;
1363  t7 = cos(t6);
1364  t8 = 1.0 + t7;
1365  t9 = t8 * t8;
1366  t10 = t9 * t8;
1367  t13 = amplitude * t9;
1368  t14 = sin(t6);
1369  t15 = t13 * t14;
1370  t16 = log(t4);
1371  t26 = t1 > 0.0 ? 1.0 : -1.0;
1372 
1373  if (t2 > width2) {
1374  *y = background;
1375 
1376  if (dyda != NULL) {
1377  dyda[LMP_WID2] = 1.0;
1378  }
1379  }
1380  else {
1381  *y = amplitude * t10 / 8.0 + background;
1382 
1383  if (dyda != NULL) {
1384 
1385  dyda[LMP_AMPL] = t10 / 8.0;
1386  dyda[LMP_CENT] = 3.0 / 8.0 * t13 * t14 * CX_PI * t5 *
1387  width1 * t26 / t2;
1388  dyda[LMP_BACK] = 1.0;
1389  dyda[LMP_WID1] = -3.0 / 8.0 * t15 * t6 * t16;
1390  dyda[LMP_WID2] = 3.0 / 8.0 * t15 * t6 * width1 * t3;
1391 
1392  }
1393  }
1394 
1395  return;
1396 
1397 }
1398 
1399 
1400 inline static void
1401 _giraffe_psfexp_ctor(GiModel *self, const GiModelData *model)
1402 {
1403 
1404  cx_assert(self != NULL);
1405  cx_assert(model != NULL);
1406 
1407  self->name = cx_strdup(model->name);
1408  self->type = model->type;
1409 
1410  self->model = model->eval;
1411 
1412 
1413  /*
1414  * Arguments
1415  */
1416 
1417  self->arguments.names = cpl_propertylist_new();
1418 
1419  cpl_propertylist_append_int(self->arguments.names, "x", 0);
1420 
1421  self->arguments.count = cpl_propertylist_get_size(self->arguments.names);
1422  self->arguments.values = cpl_matrix_new(self->arguments.count, 1);
1423 
1424 
1425  /*
1426  * Parameters
1427  */
1428 
1429  self->parameters.names = cpl_propertylist_new();
1430 
1431  cpl_propertylist_append_int(self->parameters.names, "Amplitude",
1432  LMP_AMPL);
1433  cpl_propertylist_append_int(self->parameters.names, "Center",
1434  LMP_CENT);
1435  cpl_propertylist_append_int(self->parameters.names, "Background",
1436  LMP_BACK);
1437  cpl_propertylist_append_int(self->parameters.names, "Width1",
1438  LMP_WID1);
1439  cpl_propertylist_append_int(self->parameters.names, "Width2",
1440  LMP_WID2);
1441 
1442  self->parameters.count =
1443  cpl_propertylist_get_size(self->parameters.names);
1444  self->parameters.values = cpl_matrix_new(self->parameters.count, 1);
1445 
1446  return;
1447 
1448 }
1449 
1450 
1451 inline static void
1452 _giraffe_psfexp_eval(cxdouble *y, cxdouble *x, cxdouble *a, cxint na,
1453  cxdouble *dyda, cxdouble *r)
1454 {
1455 
1456  const cxchar *const fctid = "_giraffe_psfexp_eval";
1457 
1458  cxdouble amplitude;
1459  cxdouble center;
1460  cxdouble background;
1461  cxdouble width1;
1462  cxdouble width2;
1463 
1464  cxdouble t1, t2, t3, t4, t6, t8;
1465  cxdouble t10, t15, t18;
1466 
1467 
1468  r = NULL;
1469 
1470  if (na != 5) {
1471  cpl_error_set(fctid, CPL_ERROR_ILLEGAL_INPUT);
1472  return;
1473  }
1474 
1475  *y = 0.0;
1476 
1477  if (dyda != NULL) {
1478  dyda[LMP_AMPL] = 0.;
1479  dyda[LMP_CENT] = 0.;
1480  dyda[LMP_BACK] = 0.;
1481  dyda[LMP_WID1] = 0.;
1482  dyda[LMP_WID2] = 0.;
1483  }
1484 
1485  amplitude = a[LMP_AMPL];
1486  center = a[LMP_CENT];
1487  background = a[LMP_BACK];
1488  width1 = a[LMP_WID1];
1489  width2 = a[LMP_WID2];
1490 
1491  t1 = x[0] - center;
1492 
1493  if (t1 > 0.0) {
1494  t2 = t1;
1495  t10 = 1.0;
1496  }
1497  else {
1498  t2 = -t1;
1499  t10 = -1.0;
1500  }
1501 
1502  t3 = pow(t2, width2);
1503  t4 = 1.0 / width1;
1504  t6 = exp(-t3 * t4);
1505  t8 = amplitude * t3;
1506  t15 = width1 * width1;
1507  t18 = log(t2);
1508 
1509  *y = amplitude * t6 + background;
1510 
1511  if (dyda != NULL) {
1512  dyda[LMP_AMPL] = t6;
1513  dyda[LMP_BACK] = 1.0;
1514 
1515  dyda[LMP_CENT] = t8 * width2 * t10 / t2 * t4 * t6;
1516 
1517  if (isnan(dyda[LMP_CENT])) {
1518  dyda[LMP_CENT] = 0.;
1519  }
1520 
1521  dyda[LMP_WID1] = t8 / t15 * t6;
1522 
1523  if (isnan(dyda[LMP_WID1])) {
1524  dyda[LMP_WID1] = 0.;
1525  }
1526 
1527  dyda[LMP_WID2] = -t8 * t18 * t4 * t6;
1528 
1529  if (isnan(dyda[LMP_WID2])) {
1530  dyda[LMP_WID2] = 0.;
1531  }
1532 
1533  if (r != NULL) {
1534 
1535  register cxint k;
1536 
1537  k = LMP_AMPL << 1;
1538  if (r[k + 1] > 0) {
1539  dyda[LMP_AMPL] *= _giraffe_dydaweight(a[LMP_AMPL], r[k],
1540  r[k + 1]);
1541  }
1542 
1543  k = LMP_CENT << 1;
1544  if (r[k + 1] > 0) {
1545  dyda[LMP_CENT] *= _giraffe_dydaweight(a[LMP_CENT], r[k],
1546  r[k + 1]);
1547  }
1548 
1549  k = LMP_WID1 << 1;
1550  if (r[k + 1] > 0) {
1551  dyda[LMP_WID1] *= _giraffe_dydaweight(a[LMP_WID1], r[k],
1552  r[k + 1]);
1553  }
1554 
1555  k = LMP_WID2 << 1;
1556  if (r[k + 1] > 0) {
1557  dyda[LMP_WID2] *= _giraffe_dydaweight(a[LMP_WID2], r[k],
1558  r[k + 1]);
1559  }
1560 
1561  }
1562 
1563  }
1564 
1565  return;
1566 
1567 }
1568 
1569 
1570 inline static void
1571 _giraffe_psfexp2_ctor(GiModel *self, const GiModelData *model)
1572 {
1573 
1574  cx_assert(self != NULL);
1575  cx_assert(model != NULL);
1576 
1577  self->name = cx_strdup(model->name);
1578  self->type = model->type;
1579 
1580  self->model = model->eval;
1581 
1582 
1583  /*
1584  * Arguments
1585  */
1586 
1587  self->arguments.names = cpl_propertylist_new();
1588 
1589  cpl_propertylist_append_int(self->arguments.names, "x", 0);
1590 
1591  self->arguments.count = cpl_propertylist_get_size(self->arguments.names);
1592  self->arguments.values = cpl_matrix_new(self->arguments.count, 1);
1593 
1594 
1595  /*
1596  * Parameters
1597  */
1598 
1599  self->parameters.names = cpl_propertylist_new();
1600 
1601  cpl_propertylist_append_int(self->parameters.names, "Amplitude",
1602  LMP_AMPL);
1603  cpl_propertylist_append_int(self->parameters.names, "Center",
1604  LMP_CENT);
1605  cpl_propertylist_append_int(self->parameters.names, "Background",
1606  LMP_BACK);
1607  cpl_propertylist_append_int(self->parameters.names, "Width1",
1608  LMP_WID1);
1609  cpl_propertylist_append_int(self->parameters.names, "Width2",
1610  LMP_WID2);
1611 
1612  self->parameters.count =
1613  cpl_propertylist_get_size(self->parameters.names);
1614  self->parameters.values = cpl_matrix_new(self->parameters.count, 1);
1615 
1616  return;
1617 
1618 }
1619 
1620 
1621 inline static void
1622 _giraffe_psfexp2_eval(cxdouble *y, cxdouble *x, cxdouble *a, cxint na,
1623  cxdouble *dyda, cxdouble *r)
1624 {
1625 
1626  const cxchar *const fctid = "_giraffe_psfexp2_eval";
1627 
1628  cxdouble amplitude;
1629  cxdouble center;
1630  cxdouble background;
1631  cxdouble width1;
1632  cxdouble width2;
1633 
1634  cxdouble t1, t2, t3, t4, t5, t6, t8;
1635  cxdouble t10, t16;
1636 
1637 
1638  r = NULL;
1639 
1640  if (na != 5) {
1641  cpl_error_set(fctid, CPL_ERROR_ILLEGAL_INPUT);
1642  return;
1643  }
1644 
1645  *y = 0.0;
1646 
1647  if (dyda != NULL) {
1648  dyda[LMP_AMPL] = 0.;
1649  dyda[LMP_CENT] = 0.;
1650  dyda[LMP_BACK] = 0.;
1651  dyda[LMP_WID1] = 0.;
1652  dyda[LMP_WID2] = 0.;
1653  }
1654 
1655  amplitude = a[LMP_AMPL];
1656  center = a[LMP_CENT];
1657  background = a[LMP_BACK];
1658  width1 = a[LMP_WID1];
1659  width2 = a[LMP_WID2];
1660 
1661  t1 = x[0] - center;
1662 
1663  if (t1 > 0.0) {
1664  t2 = t1;
1665  t10 = 1.0;
1666  }
1667  else {
1668  t2 = -t1;
1669  t10 = -1.0;
1670  }
1671 
1672  t3 = 1.0 / width1;
1673  t4 = t2 * t3;
1674  t5 = pow(t4, width2);
1675  t6 = exp(-t5);
1676  t8 = amplitude * t5;
1677  t16 = log(t4);
1678 
1679  *y = amplitude * t6 + background;
1680 
1681  if (dyda != NULL) {
1682 
1683  dyda[LMP_AMPL] = t6;
1684 
1685  dyda[LMP_CENT] = t8 * width2 * t10 / t2 * t6;
1686 
1687  if (isnan(dyda[LMP_CENT])) {
1688  dyda[LMP_CENT] = 0.0;
1689  }
1690 
1691  dyda[LMP_BACK] = 1.0;
1692  dyda[LMP_WID1] = t8 * width2 * t3 * t6;
1693 
1694  dyda[LMP_WID2] = -t8 * t16 * t6;
1695 
1696  if (isnan(dyda[LMP_WID2])) {
1697  dyda[LMP_WID2] = 0.0;
1698  }
1699 
1700  if (r != NULL) {
1701 
1702  register cxint k;
1703 
1704  k = LMP_AMPL << 1;
1705  if (r[k + 1] > 0) {
1706  dyda[LMP_AMPL] *= _giraffe_dydaweight(a[LMP_AMPL], r[k],
1707  r[k + 1]);
1708  }
1709 
1710  k = LMP_CENT << 1;
1711  if (r[k + 1] > 0) {
1712  dyda[LMP_CENT] *= _giraffe_dydaweight(a[LMP_CENT], r[k],
1713  r[k + 1]);
1714  }
1715 
1716  k = LMP_WID1 << 1;
1717  if (r[k + 1] > 0) {
1718  dyda[LMP_WID1] *= _giraffe_dydaweight(a[LMP_WID1], r[k],
1719  r[k + 1]);
1720  }
1721 
1722  k = LMP_WID2 << 1;
1723  if (r[k + 1] > 0) {
1724  dyda[LMP_WID2] *= _giraffe_dydaweight(a[LMP_WID2], r[k],
1725  r[k + 1]);
1726  }
1727 
1728  }
1729 
1730  }
1731 
1732  return;
1733 
1734 }
1735 
1736 
1737 inline static void
1738 _giraffe_test_ctor(GiModel *self, const GiModelData *model)
1739 {
1740 
1741  cx_assert(self != NULL);
1742  cx_assert(model != NULL);
1743 
1744  self->name = cx_strdup(model->name);
1745  self->type = model->type;
1746 
1747  self->model = model->eval;
1748 
1749 
1750  /*
1751  * Arguments
1752  */
1753 
1754  self->arguments.names = cpl_propertylist_new();
1755 
1756  cpl_propertylist_append_int(self->arguments.names, "x", 0);
1757 
1758  self->arguments.count = cpl_propertylist_get_size(self->arguments.names);
1759  self->arguments.values = cpl_matrix_new(self->arguments.count, 1);
1760 
1761 
1762  /*
1763  * Parameters
1764  */
1765 
1766  self->parameters.names = cpl_propertylist_new();
1767 
1768  cpl_propertylist_append_int(self->parameters.names, "Slope", 0);
1769  cpl_propertylist_append_int(self->parameters.names, "Intercept", 1);
1770 
1771  self->parameters.count =
1772  cpl_propertylist_get_size(self->parameters.names);
1773  self->parameters.values = cpl_matrix_new(self->parameters.count, 1);
1774 
1775  return;
1776 
1777 }
1778 
1779 
1780 inline static void
1781 _giraffe_test_eval(cxdouble *y, cxdouble *x, cxdouble *a, cxint na,
1782  cxdouble *dyda, cxdouble *r)
1783 {
1784 
1785  const cxchar *const fctid = "_giraffe_test_eval";
1786 
1787 
1788  cxdouble a1;
1789  cxdouble b1;
1790 
1791 
1792  /* Not used */
1793  (void) r;
1794 
1795  if (na != 2) {
1796  cpl_error_set(fctid, CPL_ERROR_ILLEGAL_INPUT);
1797  return;
1798  }
1799 
1800  *y = 0.0;
1801 
1802  if (dyda != NULL) {
1803  dyda[0] = 0.;
1804  dyda[1] = 0.;
1805  }
1806 
1807  a1 = a[0];
1808  b1 = a[1];
1809 
1810  *y = a1 * x[0] + b1;
1811 
1812  if (dyda != NULL) {
1813 
1814  dyda[0] = x[0];
1815  dyda[1] = 0.0;
1816 
1817  }
1818 
1819  return;
1820 
1821 }
1822 
1823 
1824 /*
1825  * Model registry
1826  */
1827 
1828 static GiModelData _gimodels[] = {
1829  {"xoptmod", GI_MODEL_XOPT,
1830  _giraffe_xoptmod_ctor, _giraffe_model_dtor, _giraffe_xoptmod_eval},
1831  {"yoptmod", GI_MODEL_YOPT,
1832  _giraffe_yoptmod_ctor, _giraffe_model_dtor, _giraffe_yoptmod_eval},
1833  {"xoptmod2", GI_MODEL_XOPT,
1834  _giraffe_xoptmod2_ctor, _giraffe_model_dtor, _giraffe_xoptmod2_eval},
1835  {"yoptmod2", GI_MODEL_XOPT,
1836  _giraffe_yoptmod2_ctor, _giraffe_model_dtor, _giraffe_yoptmod2_eval},
1837  {"gaussian", GI_MODEL_LINE,
1838  _giraffe_gaussian_ctor, _giraffe_model_dtor, _giraffe_gaussian_eval},
1839  {"psfcos", GI_MODEL_LINE,
1840  _giraffe_psfcos_ctor, _giraffe_model_dtor, _giraffe_psfcos_eval},
1841  {"psfexp", GI_MODEL_LINE,
1842  _giraffe_psfexp_ctor, _giraffe_model_dtor, _giraffe_psfexp_eval},
1843  {"psfexp2", GI_MODEL_LINE,
1844  _giraffe_psfexp2_ctor, _giraffe_model_dtor, _giraffe_psfexp2_eval},
1845  {"test", GI_MODEL_LINE,
1846  _giraffe_test_ctor, _giraffe_model_dtor, _giraffe_test_eval},
1847  {NULL, 0, NULL, NULL, NULL}
1848 };

This file is part of the GIRAFFE Pipeline Reference Manual 2.14.
Documentation copyright © 2002-2006 European Southern Observatory.
Generated on Wed Mar 11 2015 13:19:41 by doxygen 1.8.9.1 written by Dimitri van Heesch, © 1997-2004