GIRAFFE Pipeline Reference Manual

gimodels.c

00001 /* $Id: gimodels.c,v 1.10 2011/12/23 13:39:31 rpalsa Exp $
00002  *
00003  * This file is part of the GIRAFFE Pipeline
00004  * Copyright (C) 2002-2006 European Southern Observatory
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00019  */
00020 
00021 /*
00022  * $Author: rpalsa $
00023  * $Date: 2011/12/23 13:39:31 $
00024  * $Revision: 1.10 $
00025  * $Name: giraffe-2_9 $
00026  */
00027 
00028 #ifdef HAVE_CONFIG_H
00029 #  include <config.h>
00030 #endif
00031 
00032 #include <math.h>
00033 
00034 #include <cxtypes.h>
00035 #include <cxmemory.h>
00036 #include <cxmessages.h>
00037 #include <cxstrutils.h>
00038 
00039 #include "gimacros.h"
00040 #include "gimodels.h"
00041 
00042 
00043 static GiModelData _gimodels[];
00044 
00045 const GiModelData *const giraffe_models = _gimodels;
00046 
00047 
00048 /*
00049  * Optical model argument indices
00050  */
00051 
00052 enum {
00053     LMI_WLEN = 0,
00054     LMI_XFIB = 1,
00055     LMI_YFIB = 2
00056 };
00057 
00058 
00059 /*
00060  * Optical model parameter indices
00061  */
00062 
00063 enum {
00064     LMP_NX = 0,
00065     LMP_NY = 0,
00066     LMP_PXSIZ = 1,
00067     LMP_FCOLL = 2,
00068     LMP_CFACT = 3,
00069     LMP_THETA = 4,
00070     LMP_ORDER = 5,
00071     LMP_SPACE = 6,
00072     LMP_SOFFX = 7,
00073     LMP_SOFFY = 8,
00074     LMP_SPHI  = 9
00075 };
00076 
00077 
00078 /*
00079  * Line model parameter indices
00080  */
00081 
00082 enum {
00083     LMP_AMPL = 0,
00084     LMP_CENT = 1,
00085     LMP_BACK = 2,
00086     LMP_WID1 = 3,
00087     LMP_WID2 = 4
00088 };
00089 
00090 
00091 
00092 static const cxint DW_DEGREE = 3;
00093 static const cxdouble DW_LOG001 = 2.302585093;  /* -log(0.1) */
00094 
00095 
00096 /*
00097  * Utility function to calculate a weighted exponential
00098  *
00099  *                         DW_DEGREE
00100  *        exp( - | x - x0 |          )
00101  *  w = -------------------------------
00102  *           / DW_DEGREE \
00103  *           | --------- |
00104  *           \ DW_LOG001 /
00105  *        dx
00106  */
00107 
00108 inline static cxdouble
00109 _giraffe_dydaweight(cxdouble x, cxdouble x0, cxdouble dx)
00110 {
00111 
00112     register cxdouble w;
00113 
00114 
00115     w = exp(-pow(fabs(x - x0), DW_DEGREE) / pow(dx, DW_DEGREE / DW_LOG001));
00116 
00117     if (isnan(w)) {
00118         w = 1;
00119     }
00120 
00121     return w;
00122 
00123 }
00124 
00125 
00126 inline static void
00127 _giraffe_model_dtor(GiModel *self)
00128 {
00129 
00130     if (self->name) {
00131         cx_free(self->name);
00132         self->name = NULL;
00133     }
00134 
00135 
00136     self->arguments.count = 0;
00137 
00138     if (self->arguments.names) {
00139         cpl_propertylist_delete(self->arguments.names);
00140         self->arguments.names = NULL;
00141     }
00142 
00143     if (self->arguments.values) {
00144         cpl_matrix_delete(self->arguments.values);
00145         self->arguments.values = NULL;
00146     }
00147 
00148 
00149     self->parameters.count = 0;
00150 
00151     if (self->parameters.names) {
00152         cpl_propertylist_delete(self->parameters.names);
00153         self->parameters.names = NULL;
00154     }
00155 
00156     if (self->parameters.values) {
00157         cpl_matrix_delete(self->parameters.values);
00158         self->parameters.values = NULL;
00159     }
00160 
00161     if (self->parameters.limits) {
00162         cpl_matrix_delete(self->parameters.limits);
00163         self->parameters.limits = NULL;
00164     }
00165 
00166     if (self->parameters.flags) {
00167         cx_free(self->parameters.flags);
00168         self->parameters.flags = NULL;
00169     }
00170 
00171 
00172     self->fit.iterations = 0;
00173 
00174     if (self->fit.covariance) {
00175         cpl_matrix_delete(self->fit.covariance);
00176         self->fit.covariance = NULL;
00177     }
00178 
00179     return;
00180 
00181 }
00182 
00183 
00184 inline static void
00185 _giraffe_xoptmod_ctor(GiModel *self, const GiModelData *model)
00186 {
00187 
00188     cx_assert(self != NULL);
00189     cx_assert(model != NULL);
00190 
00191     self->name = cx_strdup(model->name);
00192     self->type = model->type;
00193 
00194     self->model = model->eval;
00195 
00196 
00197     /*
00198      * Arguments
00199      */
00200 
00201     self->arguments.names = cpl_propertylist_new();
00202 
00203     cpl_propertylist_append_int(self->arguments.names, "xf", LMI_XFIB);
00204     cpl_propertylist_append_int(self->arguments.names, "yf", LMI_YFIB);
00205     cpl_propertylist_append_int(self->arguments.names, "lambda", LMI_WLEN);
00206 
00207     self->arguments.count = cpl_propertylist_get_size(self->arguments.names);
00208     self->arguments.values = cpl_matrix_new(self->arguments.count, 1);
00209 
00210 
00211     /*
00212      * Parameters
00213      */
00214 
00215     self->parameters.names = cpl_propertylist_new();
00216 
00217     cpl_propertylist_append_int(self->parameters.names, "Orientation",
00218                                 LMP_NX);
00219     cpl_propertylist_append_int(self->parameters.names, "Order",
00220                                 LMP_ORDER);
00221     cpl_propertylist_append_int(self->parameters.names, "PixelSize",
00222                                 LMP_PXSIZ);
00223     cpl_propertylist_append_int(self->parameters.names, "FocalLength",
00224                                 LMP_FCOLL);
00225     cpl_propertylist_append_int(self->parameters.names, "Magnification",
00226                                 LMP_CFACT);
00227     cpl_propertylist_append_int(self->parameters.names, "Angle",
00228                                 LMP_THETA);
00229     cpl_propertylist_append_int(self->parameters.names, "Spacing",
00230                                 LMP_SPACE);
00231 
00232     self->parameters.count =
00233         cpl_propertylist_get_size(self->parameters.names);
00234     self->parameters.values = cpl_matrix_new(self->parameters.count, 1);
00235 
00236     return;
00237 
00238 }
00239 
00240 
00241 inline static void
00242 _giraffe_xoptmod_eval(cxdouble *y, cxdouble *x, cxdouble *a, cxint na,
00243                       cxdouble *dyda, cxdouble *r)
00244 {
00245 
00246     const cxchar *const fctid = "_giraffe_xoptmod_eval";
00247 
00248 
00249     cxdouble lambda;
00250     cxdouble xfibre;
00251     cxdouble yfibre;
00252 
00253     cxdouble pixsize, nx;
00254     cxdouble fcoll, cfact;
00255     cxdouble gtheta, gorder, gspace;
00256 
00257     register cxdouble xccd, d, X;
00258     register cxdouble yfibre2, tmp, tmp2, d2, X2, gspace2;
00259     register cxdouble sqtmp, costheta, sintheta;
00260 
00261 
00262 
00263     if (na != 7) {
00264         cpl_error_set(fctid, CPL_ERROR_ILLEGAL_INPUT);
00265         return;
00266     }
00267 
00268     *y = 0.0;
00269 
00270     if (dyda != NULL) {
00271         dyda[LMP_NX] = 0.;
00272         dyda[LMP_PXSIZ] = 0.;
00273         dyda[LMP_FCOLL] = 0.;
00274         dyda[LMP_CFACT] = 0.;
00275         dyda[LMP_THETA] = 0.;
00276         dyda[LMP_ORDER] = 0.;
00277         dyda[LMP_SPACE] = 0.;
00278     }
00279 
00280     lambda = x[LMI_WLEN];  /* wavelength [nm] */
00281     xfibre = x[LMI_XFIB];  /* X fibre [mm] */
00282     yfibre = x[LMI_YFIB];  /* Y fibre [mm] */
00283 
00284     nx = a[LMP_NX];             /* CCD  size along X [pixels] */
00285     pixsize = a[LMP_PXSIZ];     /* CCD pixel size [mm] */
00286     fcoll = a[LMP_FCOLL];       /* collimator focal length [mm] */
00287     cfact = a[LMP_CFACT];       /* camera magnification factor */
00288     gtheta = a[LMP_THETA];      /* grating angle [radian] */
00289     gorder = a[LMP_ORDER];      /* grating diffraction order */
00290     gspace = a[LMP_SPACE];      /* grating groove spacing [mm] */
00291 
00292 
00293     lambda *= GI_NM_TO_MM;  /* wavelength [mm] */
00294 
00295     yfibre2  = yfibre * yfibre;
00296     gspace2  = gspace * gspace;
00297     costheta = cos(gtheta);
00298     sintheta = sin(gtheta);
00299 
00300     d2 = xfibre * xfibre + yfibre2 + (fcoll * fcoll);
00301     d  = sqrt(d2);
00302 
00303     X  = (-lambda * gorder / gspace) + (xfibre * costheta / d) +
00304         (fcoll * sintheta / d);
00305     X2 = X * X;
00306 
00307     sqtmp = sqrt(1.0 - yfibre2 / d2 - X2);
00308     tmp   = -sintheta * X + costheta * sqtmp;
00309     tmp2  = tmp * tmp;
00310     xccd  = (cfact * fcoll * (X * costheta + sintheta * sqtmp)) / tmp;
00311 
00312 
00313     /*
00314      * Take care of model direction
00315      */
00316 
00317     if (nx < 0.0) {
00318         *y = xccd / pixsize - 0.5 * nx;
00319     }
00320     else {
00321         *y = -xccd / pixsize + 0.5 * nx;
00322     }
00323 
00324 
00325     /*
00326      * If requested, compute the partial derivatives of y
00327      * with respect to each parameter.
00328      */
00329 
00330     if (dyda != NULL) {
00331 
00332         dyda[LMP_NX]    = 0.5;
00333         dyda[LMP_PXSIZ] = 0.0;
00334 
00335         dyda[LMP_FCOLL] = cfact * (costheta * X + sintheta * sqtmp) / tmp +
00336             cfact * fcoll * (costheta * (-X * fcoll / d2 + sintheta / d -
00337                                          gorder * lambda * fcoll /
00338                                          (d2 * gspace)) + 0.5 * sintheta *
00339                              (-2.0 * X * (-X * fcoll / d2 + sintheta / d -
00340                                           gorder * lambda * fcoll /
00341                                           (d2 * gspace)) +
00342                               2.0 * yfibre2 * fcoll / (d2 * d2)) / sqtmp) /
00343             tmp - cfact * fcoll * (costheta * X + sintheta * sqtmp) *
00344             (-sintheta * (-X * fcoll / d2 + sintheta / d - gorder * lambda *
00345                           fcoll / (d2 * gspace)) + 0.5 * costheta *
00346              (-2.0 * X * (-X * fcoll / d2 + sintheta / d - gorder * lambda *
00347                           fcoll / (d2 * gspace)) + 2.0 * yfibre2 * fcoll /
00348               (d2 * d2)) / sqtmp) / tmp2;
00349 
00350         dyda[LMP_FCOLL] /= pixsize;
00351         dyda[LMP_CFACT] = (xccd / cfact) / pixsize;
00352 
00353         dyda[LMP_THETA] = cfact * fcoll * ((-xfibre * sintheta / d + fcoll *
00354                                             costheta / d) * costheta -
00355                                            sintheta * X - sintheta * X *
00356                                            (-xfibre * sintheta / d + fcoll *
00357                                             costheta / d) / sqtmp +
00358                                            costheta * sqtmp) / tmp -
00359             cfact * fcoll * (costheta * X + sintheta * sqtmp) *
00360             (-(-xfibre * sintheta / d + fcoll * costheta / d) * sintheta -
00361              costheta * X - costheta * X * (-xfibre * sintheta / d + fcoll *
00362                                             costheta / d) /
00363              sqtmp - sintheta * sqtmp) / tmp2;
00364 
00365         dyda[LMP_THETA] /= pixsize;
00366         dyda[LMP_ORDER] = 0.0;
00367 
00368         dyda[LMP_SPACE] = cfact * fcoll * (lambda * gorder * costheta /
00369                                            gspace2 - sintheta * X * lambda *
00370                                            gorder / (sqtmp * gspace2)) /
00371             tmp - cfact * fcoll * (X * costheta + sintheta * sqtmp) *
00372             (-lambda * gorder * sintheta / gspace2 - costheta * X * lambda *
00373              gorder / (sqtmp * gspace2)) / tmp2;
00374 
00375         dyda[LMP_SPACE] /= pixsize;
00376 
00377         if (nx > 0.) {
00378             dyda[LMP_NX]    = -dyda[LMP_NX];
00379             dyda[LMP_PXSIZ] = -dyda[LMP_PXSIZ];
00380             dyda[LMP_FCOLL] = -dyda[LMP_FCOLL];
00381             dyda[LMP_CFACT] = -dyda[LMP_CFACT];
00382             dyda[LMP_THETA] = -dyda[LMP_THETA];
00383             dyda[LMP_ORDER] = -dyda[LMP_ORDER];
00384             dyda[LMP_SPACE] = -dyda[LMP_SPACE];
00385         }
00386 
00387         if (r != NULL) {
00388 
00389             register cxint k;
00390 
00391             k = LMP_FCOLL << 1;
00392             if (r[k+1] > 0) {
00393                 dyda[LMP_FCOLL] *= _giraffe_dydaweight(a[LMP_FCOLL], r[k],
00394                                                        r[k + 1]);
00395             }
00396 
00397             k = LMP_CFACT << 1;
00398             if (r[k+1] > 0) {
00399                 dyda[LMP_CFACT] *= _giraffe_dydaweight(a[LMP_CFACT], r[k],
00400                                                        r[k + 1]);
00401             }
00402 
00403             k = LMP_THETA << 1;
00404             if (r[k+1] > 0) {
00405                 dyda[LMP_THETA] *= _giraffe_dydaweight(a[LMP_THETA], r[k],
00406                                                        r[k + 1]);
00407             }
00408 
00409             k = LMP_SPACE << 1;
00410             if (r[k+1] > 0) {
00411                 dyda[LMP_SPACE] *= _giraffe_dydaweight(a[LMP_SPACE], r[k],
00412                                                        r[k + 1]);
00413             }
00414 
00415         }
00416 
00417     }
00418 
00419     return;
00420 
00421 }
00422 
00423 
00424 inline static void
00425 _giraffe_yoptmod_ctor(GiModel *self, const GiModelData *model)
00426 {
00427 
00428     cx_assert(self != NULL);
00429     cx_assert(model != NULL);
00430 
00431     self->name = cx_strdup(model->name);
00432     self->type = model->type;
00433 
00434     self->model = model->eval;
00435 
00436 
00437     /*
00438      * Arguments
00439      */
00440 
00441     self->arguments.names = cpl_propertylist_new();
00442 
00443     cpl_propertylist_append_int(self->arguments.names, "xf", LMI_XFIB);
00444     cpl_propertylist_append_int(self->arguments.names, "yf", LMI_YFIB);
00445     cpl_propertylist_append_int(self->arguments.names, "lambda", LMI_WLEN);
00446 
00447     self->arguments.count = cpl_propertylist_get_size(self->arguments.names);
00448     self->arguments.values = cpl_matrix_new(self->arguments.count, 1);
00449 
00450 
00451     /*
00452      * Parameters
00453      */
00454 
00455     self->parameters.names = cpl_propertylist_new();
00456 
00457     cpl_propertylist_append_int(self->parameters.names, "Orientation",
00458                                 LMP_NY);
00459     cpl_propertylist_append_int(self->parameters.names, "Order",
00460                                 LMP_ORDER);
00461     cpl_propertylist_append_int(self->parameters.names, "PixelSize",
00462                                 LMP_PXSIZ);
00463     cpl_propertylist_append_int(self->parameters.names, "FocalLength",
00464                                 LMP_FCOLL);
00465     cpl_propertylist_append_int(self->parameters.names, "Magnification",
00466                                 LMP_CFACT);
00467     cpl_propertylist_append_int(self->parameters.names, "Angle",
00468                                 LMP_THETA);
00469     cpl_propertylist_append_int(self->parameters.names, "Spacing",
00470                                 LMP_SPACE);
00471 
00472     self->parameters.count =
00473         cpl_propertylist_get_size(self->parameters.names);
00474     self->parameters.values = cpl_matrix_new(self->parameters.count, 1);
00475 
00476     return;
00477 
00478 }
00479 
00480 
00481 inline static void
00482 _giraffe_yoptmod_eval(cxdouble *y, cxdouble *x, cxdouble *a, cxint na,
00483                       cxdouble *dyda, cxdouble *r)
00484 {
00485 
00486     const cxchar *const fctid = "_giraffe_yoptmod_eval";
00487 
00488     cxdouble lambda, xfibre, yfibre;
00489     cxdouble pixsize, ny;
00490     cxdouble fcoll,cfact;
00491     cxdouble gtheta,gorder,gspace;
00492 
00493     register cxdouble t2, t3, t4, t5, t6, t7, t8, t9;
00494     register cxdouble t10, t12, t13, t15, t18;
00495     register cxdouble t22, t24, t26, t27, t28, t29;
00496     register cxdouble t30, t33;
00497     register cxdouble t41, t45, t47;
00498     register cxdouble t53, t56, t57;
00499     register cxdouble t76;
00500     register cxdouble t93, t94;
00501 
00502 
00503     /* Not used */
00504     r = NULL;
00505 
00506     if (na != 7) {
00507         cpl_error_set(fctid, CPL_ERROR_ILLEGAL_INPUT);
00508         return;
00509     }
00510 
00511     *y = 0.;
00512 
00513     if (dyda != NULL) {
00514         dyda[LMP_NY] = 0.;
00515         dyda[LMP_PXSIZ] = 0.;
00516         dyda[LMP_FCOLL] = 0.;
00517         dyda[LMP_CFACT] = 0.;
00518         dyda[LMP_THETA] = 0.;
00519         dyda[LMP_ORDER] = 0.;
00520         dyda[LMP_SPACE] = 0.;
00521     }
00522 
00523     lambda  = x[LMI_WLEN];
00524     xfibre  = x[LMI_XFIB];
00525     yfibre  = x[LMI_YFIB];
00526 
00527     ny      = a[LMP_NY];
00528     pixsize = a[LMP_PXSIZ];
00529     fcoll   = a[LMP_FCOLL];
00530     cfact   = a[LMP_CFACT];
00531     gtheta  = a[LMP_THETA];
00532     gorder  = a[LMP_ORDER];
00533     gspace  = a[LMP_SPACE];
00534 
00535     lambda *= GI_NM_TO_MM;
00536 
00537     t2 = cfact * fcoll * yfibre;
00538     t3 = xfibre * xfibre;
00539     t4 = yfibre * yfibre;
00540     t5 = fcoll * fcoll;
00541     t6 = t3 + t4 + t5;
00542     t7 = sqrt(t6);
00543     t8 = 1.0 / t7;
00544     t9 = lambda * gorder;
00545     t10 = 1.0 / gspace;
00546     t12 = cos(gtheta);
00547     t13 = xfibre * t12;
00548     t15 = sin(gtheta);
00549     t18 = -t9 * t10 + t13 * t8 + fcoll * t15 * t8;
00550     t22 = t18 * t18;
00551     t24 = sqrt(1.0 - t4 / t6 - t22);
00552     t26 = -t18 * t15 + t12 * t24;
00553     t27 = 1.0 / t26;
00554     t28 = t8 * t27;
00555     t29 = 1.0 / pixsize;
00556     t30 = t28 * t29;
00557     t33 = pixsize * pixsize;
00558     t41 = 1.0 / t7 / t6;
00559     t45 = t26 * t26;
00560     t47 = t8 / t45;
00561     t53 = -t13 * t41 * fcoll + t15 * t8 - t5 * t15 * t41;
00562     t56 = t12 / t24;
00563     t57 = t6 * t6;
00564     t76 = -xfibre * t15 * t8 + fcoll * t12 * t8;
00565     t93 = gspace * gspace;
00566     t94 = 1.0 / t93;
00567 
00568     *y = -t2 * t30 + 0.5 * ny;
00569 
00570 
00571     /*
00572      * If requested, compute the partial derivatives of y
00573      * with respect to each parameter.
00574      */
00575 
00576     if (dyda != NULL) {
00577 
00578         dyda[LMP_NY] = 0.5;
00579         dyda[LMP_PXSIZ] = t2 * t28 / t33;
00580         dyda[LMP_FCOLL] = -cfact * yfibre * t30 + cfact * t5 *
00581             yfibre * t41 * t27 * t29 + t2 * t47 * t29 *
00582             (-t53 * t15 + t56 * (2.0 * t4 / t57 * fcoll -
00583                                  2.0 * t18 * t53) / 2.0);
00584         dyda[LMP_CFACT] = -fcoll * yfibre * t30;
00585         dyda[LMP_THETA] = t2 * t47 * t29 * (-t76 * t15 - t18 * t12 -
00586                                             t15 * t24 - t56 * t18 * t76);
00587         dyda[LMP_ORDER] = t2 * t47 *t29 *(lambda * t10 * t15 + t56 *
00588                                           t18 * lambda * t10);
00589         dyda[LMP_SPACE] = t2 * t47 * t29 * (-t9 * t94 * t15 -
00590                                             t56 * t18 * t9 * t94);
00591 
00592     }
00593 
00594     return;
00595 
00596 }
00597 
00598 
00599 inline static void
00600 _giraffe_xoptmod2_ctor(GiModel *self, const GiModelData *model)
00601 {
00602 
00603     cx_assert(self != NULL);
00604     cx_assert(model != NULL);
00605 
00606     self->name = cx_strdup(model->name);
00607     self->type = model->type;
00608 
00609     self->model = model->eval;
00610 
00611 
00612     /*
00613      * Arguments
00614      */
00615 
00616     self->arguments.names = cpl_propertylist_new();
00617 
00618     cpl_propertylist_append_int(self->arguments.names, "xf", LMI_XFIB);
00619     cpl_propertylist_append_int(self->arguments.names, "yf", LMI_YFIB);
00620     cpl_propertylist_append_int(self->arguments.names, "lambda", LMI_WLEN);
00621 
00622     self->arguments.count = cpl_propertylist_get_size(self->arguments.names);
00623     self->arguments.values = cpl_matrix_new(self->arguments.count, 1);
00624 
00625 
00626     /*
00627      * Parameters
00628      */
00629 
00630     self->parameters.names = cpl_propertylist_new();
00631 
00632     cpl_propertylist_append_int(self->parameters.names, "Orientation",
00633                                 LMP_NX);
00634     cpl_propertylist_append_int(self->parameters.names, "Order",
00635                                 LMP_ORDER);
00636     cpl_propertylist_append_int(self->parameters.names, "PixelSize",
00637                                 LMP_PXSIZ);
00638     cpl_propertylist_append_int(self->parameters.names, "FocalLength",
00639                                 LMP_FCOLL);
00640     cpl_propertylist_append_int(self->parameters.names, "Magnification",
00641                                 LMP_CFACT);
00642     cpl_propertylist_append_int(self->parameters.names, "Angle",
00643                                 LMP_THETA);
00644     cpl_propertylist_append_int(self->parameters.names, "Spacing",
00645                                 LMP_SPACE);
00646     cpl_propertylist_append_int(self->parameters.names, "Sdx",
00647                                 LMP_SOFFX);
00648     cpl_propertylist_append_int(self->parameters.names, "Sdy",
00649                                 LMP_SOFFY);
00650     cpl_propertylist_append_int(self->parameters.names, "Sphi",
00651                                 LMP_SPHI);
00652 
00653     self->parameters.count =
00654         cpl_propertylist_get_size(self->parameters.names);
00655     self->parameters.values = cpl_matrix_new(self->parameters.count, 1);
00656 
00657     return;
00658 
00659 }
00660 
00661 
00662 inline static void
00663 _giraffe_xoptmod2_eval(cxdouble *y, cxdouble *x, cxdouble *a, cxint na,
00664                        cxdouble *dyda, cxdouble *r)
00665 {
00666 
00667     const cxchar *const fctid = "_giraffe_xoptmod2_eval";
00668 
00669 
00670     cxdouble lambda;
00671     cxdouble xfibre;
00672     cxdouble yfibre;
00673 
00674     cxdouble pixsize, nx;
00675     cxdouble fcoll, cfact;
00676     cxdouble gtheta, gorder, gspace;
00677     cxdouble slitdx, slitdy, slitphi;
00678 
00679     register cxdouble t1, t2, t3, t4, t9;
00680     register cxdouble t10, t11, t12, t14, t16, t17, t18, t19;
00681     register cxdouble t20, t21, t23, t24, t26, t27, t28;
00682     register cxdouble t30, t32, t33, t34, t35, t36, t37, t38, t39;
00683     register cxdouble t40, t44, t49;
00684     register cxdouble t52, t58;
00685     register cxdouble t60, t61, t62, t64, t68;
00686     register cxdouble t75, t76, t78;
00687     register cxdouble t80;
00688     register cxdouble t91, t93;
00689     register cxdouble t104, t107;
00690     register cxdouble t113, t119;
00691     register cxdouble t120, t121, t124;
00692     register cxdouble t136, t137, t138;
00693     register cxdouble t143, t148;
00694     register cxdouble t161, t162, t166, t168;
00695     register cxdouble t173;
00696     register cxdouble t191, t195, t196;
00697     register cxdouble t201, t210;
00698 
00699 
00700     if (na != 10) {
00701         cpl_error_set(fctid, CPL_ERROR_ILLEGAL_INPUT);
00702         return;
00703     }
00704 
00705     *y = 0.0;
00706 
00707     if (dyda != NULL) {
00708         dyda[LMP_NX] = 0.;
00709         dyda[LMP_PXSIZ] = 0.;
00710         dyda[LMP_FCOLL] = 0.;
00711         dyda[LMP_CFACT] = 0.;
00712         dyda[LMP_THETA] = 0.;
00713         dyda[LMP_ORDER] = 0.;
00714         dyda[LMP_SPACE] = 0.;
00715         dyda[LMP_SOFFX] = 0.;
00716         dyda[LMP_SOFFY] = 0.;
00717         dyda[LMP_SPHI] = 0.;
00718     }
00719 
00720     lambda  = x[LMI_WLEN];    /* wavelength [nm] */
00721     xfibre  = x[LMI_XFIB];    /* Y fibre [mm] */
00722     yfibre  = x[LMI_YFIB];    /* Y fibre [mm] */
00723 
00724     nx      = a[LMP_NX];      /* CCD  size in X [pixels] */
00725     pixsize = a[LMP_PXSIZ];   /* CCD pixel size [mm] */
00726     fcoll   = a[LMP_FCOLL];   /* collimator focal length [mm] */
00727     cfact   = a[LMP_CFACT];   /* camera magnification factor */
00728     gtheta  = a[LMP_THETA];   /* grating angle [radian] */
00729     gorder  = a[LMP_ORDER];   /* grating diffraction order */
00730     gspace  = a[LMP_SPACE];   /* grating groove spacing [mm] */
00731     slitdx  = a[LMP_SOFFX];   /* slit position x offset [mm] */
00732     slitdy  = a[LMP_SOFFY];   /* slit position y offset [mm] */
00733     slitphi = a[LMP_SPHI];    /* slit position angle [radian] */
00734 
00735     lambda *= GI_NM_TO_MM;  /* wavelength [mm] */
00736 
00737     t1 = cfact * fcoll;
00738     t2 = cos(gtheta);
00739     t3 = lambda * gorder;
00740     t4 = 1.0 / gspace;
00741     t9 = xfibre * (1.0 + slitphi * yfibre) + slitdx;
00742     t10 = t9 * t2;
00743     t11 = t9 * t9;
00744     t12 = slitphi * slitphi;
00745     t14 = sqrt(1.0 - t12);
00746     t16 = yfibre * t14 + slitdy;
00747     t17 = t16 * t16;
00748     t18 = fcoll * fcoll;
00749     t19 = t11 + t17 + t18;
00750     t20 = sqrt(t19);
00751     t21 = 1.0 / t20;
00752     t23 = sin(gtheta);
00753     t24 = fcoll * t23;
00754     t26 = -t3 * t4 + t10 * t21 + t24 * t21;
00755     t27 = t2 * t26;
00756     t28 = 1.0 / t19;
00757     t30 = t26 * t26;
00758     t32 = sqrt(1.0 - t17 * t28 - t30);
00759     t33 = t23 * t32;
00760     t34 = t27 + t33;
00761     t35 = t23 * t26;
00762     t36 = t2 * t32;
00763     t37 = -t35 + t36;
00764     t38 = 1.0 / t37;
00765     t39 = t34 * t38;
00766     t40 = 1.0 / pixsize;
00767     t44 = pixsize * pixsize;
00768     t49 = t38 * t40;
00769     t52 = 1.0 / t20 / t19;
00770     t58 = -t10 * t52 * fcoll + t23 * t21 - t18 * t23 * t52;
00771     t60 = 1.0 / t32;
00772     t61 = t23 * t60;
00773     t62 = t19 * t19;
00774     t64 = t17 / t62;
00775     t68 = 2.0 * t64 * fcoll - 2.0 * t26 * t58;
00776     t75 = t1 * t34;
00777     t76 = t37 * t37;
00778     t78 = 1.0 / t76 * t40;
00779     t80 = t2 * t60;
00780     t91 = -t9 * t23 * t21 + fcoll * t2 * t21;
00781     t93 = t26 * t91;
00782     t104 = t2 * lambda;
00783     t107 = t26 * lambda * t4;
00784     t113 = t23 * lambda;
00785     t119 = gspace * gspace;
00786     t120 = 1.0 / t119;
00787     t121 = gorder * t120;
00788     t124 = t3 * t120;
00789     t136 = t2 * t21;
00790     t137 = 2.0 * t9;
00791     t138 = t52 * t137;
00792     t143 = t136 - t10 * t138 / 2.0 - t24 * t138 / 2.0;
00793     t148 = t64 * t137 - 2.0 * t26 * t143;
00794     t161 = 2.0 * t16;
00795     t162 = t52 * t161;
00796     t166 = -t10 * t162 / 2.0 - t24 * t162 / 2.0;
00797     t168 = t16 * t28;
00798     t173 = -2.0 * t168 + t64 * t161 - 2.0 * t26 * t166;
00799     t191 = 1.0 / t14;
00800     t195 = 2.0 * t9 * xfibre * yfibre - 2.0 * t16 * yfibre * t191 * slitphi;
00801     t196 = t52 * t195;
00802     t201 = xfibre * yfibre * t136 - t10 * t196 / 2.0 - t24 * t196 / 2.0;
00803     t210 = 2.0 * t168 * yfibre * t191 * slitphi + t64 * t195 -
00804         2.0 * t26 * t201;
00805 
00806 
00807     /*
00808      * Take care of model direction
00809      */
00810 
00811     if (nx < 0.0) {
00812         *y = t1 * t39 * t40 - 0.5 * nx;
00813     }
00814     else {
00815         *y = -t1 * t39 * t40 + 0.5 * nx;
00816     }
00817 
00818 
00819     /*
00820      * If requested, compute the partial derivatives of y
00821      * with respect to each parameter.
00822      */
00823 
00824     if (dyda != NULL) {
00825 
00826         dyda[LMP_NX] = 0.5;
00827         dyda[LMP_PXSIZ] = -t1 * t39 / t44;
00828         dyda[LMP_FCOLL] = cfact * t34 * t49 + t1 *
00829             (t2 * t58 + t61 * t68 / 2.0) * t38 * t40 -
00830             t75 * t78 * (-t23 * t58 + t80 * t68 / 2.0);
00831         dyda[LMP_CFACT] = fcoll * t34 * t49;
00832         dyda[LMP_THETA] = t1 * (-t35 + t2 * t91 + t36 - t61 * t93) * t38 *
00833             t40 - t75 * t78 * (-t27 - t23 * t91 - t33 - t80 * t93);
00834         dyda[LMP_ORDER] = t1 * (-t104 * t4 + t61 * t107) * t38 * t40 - t75 *
00835             t78 * (t113 * t4 + t80 * t107);
00836         dyda[LMP_SPACE] = t1 * (t104 * t121 - t61 * t26 * t124) * t38 * t40 -
00837             t75 * t78 * (-t113 * t121 - t80 * t26 * t124);
00838         dyda[LMP_SOFFX] = t1 * (t2 * t143 + t61 * t148 / 2.0) * t38 * t40 -
00839             t75 * t78 * (-t23 * t143 + t80 * t148 / 2.0);
00840         dyda[LMP_SOFFY] = t1 * (t2 * t166 + t61 * t173 / 2.0) * t38 * t40 -
00841             t75 * t78 * (-t23 * t166 + t80 * t173 / 2.0);
00842         dyda[LMP_SPHI]  = t1 * (t2 * t201 + t61 * t210 / 2.0) * t38 * t40 -
00843             t75 * t78 * (-t23 * t201 + t80 * t210 / 2.0);
00844 
00845         if (nx > 0.0) {
00846             dyda[LMP_NX]    = -dyda[LMP_NX];
00847             dyda[LMP_PXSIZ] = -dyda[LMP_PXSIZ];
00848             dyda[LMP_FCOLL] = -dyda[LMP_FCOLL];
00849             dyda[LMP_CFACT] = -dyda[LMP_CFACT];
00850             dyda[LMP_THETA] = -dyda[LMP_THETA];
00851             dyda[LMP_ORDER] = -dyda[LMP_ORDER];
00852             dyda[LMP_SPACE] = -dyda[LMP_SPACE];
00853             dyda[LMP_SOFFX] = -dyda[LMP_SOFFX];
00854             dyda[LMP_SOFFY] = -dyda[LMP_SOFFY];
00855             dyda[LMP_SPHI]  = -dyda[LMP_SPHI];
00856         }
00857 
00858         if (r != NULL) {
00859 
00860             register cxint k;
00861 
00862 
00863             k = LMP_PXSIZ << 1;
00864             if (r[k + 1] > 0) {
00865                 dyda[LMP_PXSIZ] *= _giraffe_dydaweight(a[LMP_PXSIZ], r[k],
00866                                                        r[k + 1]);
00867             }
00868 
00869             k = LMP_FCOLL << 1;
00870             if (r[k + 1] > 0) {
00871                 dyda[LMP_FCOLL] *= _giraffe_dydaweight(a[LMP_FCOLL], r[k],
00872                                                        r[k + 1]);
00873             }
00874 
00875             k = LMP_CFACT << 1;
00876             if (r[k + 1] > 0) {
00877                 dyda[LMP_CFACT] *= _giraffe_dydaweight(a[LMP_CFACT], r[k],
00878                                                        r[k + 1]);
00879             }
00880 
00881             k = LMP_THETA << 1;
00882             if (r[k + 1] > 0) {
00883                 dyda[LMP_THETA] *=  _giraffe_dydaweight(a[LMP_THETA], r[k],
00884                                                         r[k + 1]);
00885             }
00886 
00887             k = LMP_ORDER << 1;
00888             if (r[k + 1] > 0) {
00889                 dyda[LMP_ORDER] *=  _giraffe_dydaweight(a[LMP_ORDER], r[k],
00890                                                         r[k + 1]);
00891             }
00892 
00893             k = LMP_SPACE << 1;
00894             if (r[k + 1] > 0) {
00895                 dyda[LMP_SPACE] *=  _giraffe_dydaweight(a[LMP_SPACE], r[k],
00896                                                         r[k + 1]);
00897             }
00898 
00899             k = LMP_SOFFX << 1;
00900             if (r[k + 1] > 0) {
00901                 dyda[LMP_SOFFX] *=  _giraffe_dydaweight(a[LMP_SOFFX], r[k],
00902                                                         r[k + 1]);
00903             }
00904 
00905             k = LMP_SOFFY << 1;
00906             if (r[k + 1] > 0) {
00907                 dyda[LMP_SOFFY] *=  _giraffe_dydaweight(a[LMP_SOFFY], r[k],
00908                                                         r[k + 1]);
00909             }
00910 
00911             k = LMP_SPHI << 1;
00912             if (r[k + 1] > 0) {
00913                 dyda[LMP_SPHI] *=  _giraffe_dydaweight(a[LMP_SPHI], r[k],
00914                                                        r[k + 1]);
00915             }
00916 
00917         }
00918 
00919     }
00920 
00921     return;
00922 
00923 }
00924 
00925 
00926 inline static void
00927 _giraffe_yoptmod2_ctor(GiModel *self, const GiModelData *model)
00928 {
00929 
00930     cx_assert(self != NULL);
00931     cx_assert(model != NULL);
00932 
00933     self->name = cx_strdup(model->name);
00934     self->type = model->type;
00935 
00936     self->model = model->eval;
00937 
00938 
00939     /*
00940      * Arguments
00941      */
00942 
00943     self->arguments.names = cpl_propertylist_new();
00944 
00945     cpl_propertylist_append_int(self->arguments.names, "xf", LMI_XFIB);
00946     cpl_propertylist_append_int(self->arguments.names, "yf", LMI_YFIB);
00947     cpl_propertylist_append_int(self->arguments.names, "lambda", LMI_WLEN);
00948 
00949     self->arguments.count = cpl_propertylist_get_size(self->arguments.names);
00950     self->arguments.values = cpl_matrix_new(self->arguments.count, 1);
00951 
00952 
00953     /*
00954      * Parameters
00955      */
00956 
00957     self->parameters.names = cpl_propertylist_new();
00958 
00959     cpl_propertylist_append_int(self->parameters.names, "Orientation",
00960                                 LMP_NY);
00961     cpl_propertylist_append_int(self->parameters.names, "Order",
00962                                 LMP_ORDER);
00963     cpl_propertylist_append_int(self->parameters.names, "PixelSize",
00964                                 LMP_PXSIZ);
00965     cpl_propertylist_append_int(self->parameters.names, "FocalLength",
00966                                 LMP_FCOLL);
00967     cpl_propertylist_append_int(self->parameters.names, "Magnification",
00968                                 LMP_CFACT);
00969     cpl_propertylist_append_int(self->parameters.names, "Angle",
00970                                 LMP_THETA);
00971     cpl_propertylist_append_int(self->parameters.names, "Spacing",
00972                                 LMP_SPACE);
00973     cpl_propertylist_append_int(self->parameters.names, "Sdx",
00974                                 LMP_SOFFX);
00975     cpl_propertylist_append_int(self->parameters.names, "Sdy",
00976                                 LMP_SOFFY);
00977     cpl_propertylist_append_int(self->parameters.names, "Sphi",
00978                                 LMP_SPHI);
00979 
00980     self->parameters.count =
00981         cpl_propertylist_get_size(self->parameters.names);
00982     self->parameters.values = cpl_matrix_new(self->parameters.count, 1);
00983 
00984     return;
00985 
00986 }
00987 
00988 
00989 inline static void
00990 _giraffe_yoptmod2_eval(cxdouble *y, cxdouble *x, cxdouble *a, cxint na,
00991                        cxdouble *dyda, cxdouble *r)
00992 {
00993 
00994     const cxchar *const fctid = "_giraffe_yoptmod2_eval";
00995 
00996 
00997     cxdouble lambda, xfibre, yfibre;
00998     cxdouble pixsize, ny;
00999     cxdouble fcoll, cfact;
01000     cxdouble gtheta, gorder, gspace;
01001     cxdouble slitdx, slitdy, slitphi;
01002 
01003     register cxdouble t1, t2, t4, t6, t7;
01004     register cxdouble t11, t12, t13, t14, t15, t16, t17, t18, t19;
01005     register cxdouble t21, t22, t24, t25, t27, t29;
01006     register cxdouble t31, t33, t35, t36, t37, t38, t39;
01007     register cxdouble t42, t50, t51, t54, t56;
01008     register cxdouble t62, t65, t66, t68;
01009     register cxdouble t85;
01010     register cxdouble t102, t103;
01011     register cxdouble t112, t117, t118;
01012     register cxdouble t123;
01013     register cxdouble t136;
01014     register cxdouble t141, t145, t147;
01015     register cxdouble t159;
01016     register cxdouble t160;
01017     register cxdouble t172, t179;
01018     register cxdouble t184;
01019 
01020 
01021     /* Not used */
01022     r = NULL;
01023 
01024     if (na != 10) {
01025         cpl_error_set(fctid, CPL_ERROR_ILLEGAL_INPUT);
01026         return;
01027     }
01028 
01029     *y = 0.0;
01030 
01031     if (dyda != NULL) {
01032         dyda[LMP_NY] = 0.;
01033         dyda[LMP_PXSIZ] = 0.;
01034         dyda[LMP_FCOLL] = 0.;
01035         dyda[LMP_CFACT] = 0.;
01036         dyda[LMP_THETA] = 0.;
01037         dyda[LMP_ORDER] = 0.;
01038         dyda[LMP_SPACE] = 0.;
01039         dyda[LMP_SOFFX] = 0.;
01040         dyda[LMP_SOFFY] = 0.;
01041         dyda[LMP_SPHI] = 0.;
01042     }
01043 
01044     lambda  = x[LMI_WLEN];
01045     xfibre  = x[LMI_XFIB];
01046     yfibre  = x[LMI_YFIB];
01047 
01048     ny      = a[LMP_NY];
01049     pixsize = a[LMP_PXSIZ];
01050     fcoll   = a[LMP_FCOLL];
01051     cfact   = a[LMP_CFACT];
01052     gtheta  = a[LMP_THETA];
01053     gorder  = a[LMP_ORDER];
01054     gspace  = a[LMP_SPACE];
01055     slitdx  = a[LMP_SOFFX];
01056     slitdy  = a[LMP_SOFFY];
01057     slitphi = a[LMP_SPHI];
01058 
01059     lambda *= GI_NM_TO_MM;
01060 
01061     t1 = cfact * fcoll;
01062     t2 = slitphi * slitphi;
01063     t4 = sqrt(1.0 - t2);
01064     t6 = yfibre * t4 + slitdy;
01065     t7 = t1 * t6;
01066     t11 = xfibre * (1.0 + slitphi * yfibre) + slitdx;
01067     t12 = t11 * t11;
01068     t13 = t6 * t6;
01069     t14 = fcoll * fcoll;
01070     t15 = t12 + t13 + t14;
01071     t16 = sqrt(t15);
01072     t17 = 1 / t16;
01073     t18 = lambda * gorder;
01074     t19 = 1 / gspace;
01075     t21 = cos(gtheta);
01076     t22 = t11 * t21;
01077     t24 = sin(gtheta);
01078     t25 = fcoll * t24;
01079     t27 = -t18 * t19 + t22 * t17 + t25 * t17;
01080     t29 = 1 / t15;
01081     t31 = t27 * t27;
01082     t33 = sqrt(1.0 - t13 * t29 - t31);
01083     t35 = -t27 * t24 + t21 * t33;
01084     t36 = 1 / t35;
01085     t37 = t17 * t36;
01086     t38 = 1 / pixsize;
01087     t39 = t37 * t38;
01088     t42 = pixsize * pixsize;
01089     t50 = 1 / t16 / t15;
01090     t51 = t50 * t36;
01091     t54 = t35 * t35;
01092     t56 = t17 / t54;
01093     t62 = -t22 * t50 * fcoll + t24 * t17 - t14 * t24 * t50;
01094     t65 = t21 / t33;
01095     t66 = t15 * t15;
01096     t68 = t13 / t66;
01097     t85 = -t11 * t24 * t17 + fcoll * t21 * t17;
01098     t102 = gspace * gspace;
01099     t103 = 1 / t102;
01100     t112 = 2.0 * t11;
01101     t117 = t21 * t17;
01102     t118 = t50 * t112;
01103     t123 = t117 - t22 * t118 / 2.0 - t25 * t118 / 2.0;
01104     t136 = 2.0 * t6;
01105     t141 = t50 * t136;
01106     t145 = -t22 * t141 / 2.0 - t25 * t141 / 2.0;
01107     t147 = t6 * t29;
01108     t159 = 1 / t4;
01109     t160 = yfibre * t159;
01110     t172 = 2.0 * t11 * xfibre * yfibre - 2.0 * t6 * yfibre * t159 * slitphi;
01111     t179 = t50 * t172;
01112     t184 = xfibre * yfibre * t117 - t22 * t179 / 2.0 - t25 * t179 / 2.0;
01113 
01114     *y = -t7 * t39 + 0.5 * ny;
01115 
01116     if (dyda != NULL) {
01117 
01118         dyda[LMP_NY] = 0.5;
01119         dyda[LMP_PXSIZ] = t7 * t37 / t42;
01120         dyda[LMP_FCOLL] = -cfact * t6 * t39 + cfact * t14 * t6 * t51 * t38 +
01121             t7 * t56 * t38 * (-t62 * t24 + t65 * (2.0 * t68 * fcoll -
01122                                                   2.0 * t27 * t62) / 2.0);
01123         dyda[LMP_CFACT] = -fcoll * t6 * t39;
01124         dyda[LMP_THETA] = t7 * t56 * t38 * (-t85 * t24 - t27 * t21 - t24 *
01125                                             t33 - t65 * t27 * t85);
01126         dyda[LMP_ORDER] = t7 * t56 * t38 * (lambda * t19 * t24 + t65 * t27 *
01127                                             lambda * t19);
01128         dyda[LMP_SPACE] = t7 * t56 * t38 * (-t18 * t103 * t24 - t65 * t27 *
01129                                             t18 * t103);
01130         dyda[LMP_SOFFX] = t7 * t51 * t38 * t112 / 2.0 + t7 * t56 * t38 *
01131             (-t123 * t24 + t65 * (t68 * t112 - 2.0 * t27 * t123) / 2.0);
01132         dyda[LMP_SOFFY] = -t1 * t39 + t7 * t51 * t38 * t136 / 2.0 + t7 *
01133             t56 * t38 * (-t145 * t24 + t65 * (-2.0 * t147 + t68 * t136 -
01134                                               2.0 * t27 * t145) / 2.0);
01135         dyda[LMP_SPHI]  = t1 * t160 * slitphi * t17 * t36 * t38 + t7 * t51 *
01136             t38 * t172 / 2.0 + t7 * t56 * t38 *
01137             (-t184 * t24 + t65 * (2.0 * t147 * t160 * slitphi + t68 * t172 -
01138                                   2.0 * t27 * t184) / 2.0);
01139 
01140     }
01141 
01142     return;
01143 
01144 }
01145 
01146 
01147 inline static void
01148 _giraffe_gaussian_ctor(GiModel *self, const GiModelData *model)
01149 {
01150 
01151     cx_assert(self != NULL);
01152     cx_assert(model != NULL);
01153 
01154     self->name = cx_strdup(model->name);
01155     self->type = model->type;
01156 
01157     self->model = model->eval;
01158 
01159 
01160     /*
01161      * Arguments
01162      */
01163 
01164     self->arguments.names = cpl_propertylist_new();
01165 
01166     cpl_propertylist_append_int(self->arguments.names, "x", 0);
01167 
01168     self->arguments.count = cpl_propertylist_get_size(self->arguments.names);
01169     self->arguments.values = cpl_matrix_new(self->arguments.count, 1);
01170 
01171 
01172     /*
01173      * Parameters
01174      */
01175 
01176     self->parameters.names = cpl_propertylist_new();
01177 
01178     cpl_propertylist_append_int(self->parameters.names, "Amplitude",
01179                                 LMP_AMPL);
01180     cpl_propertylist_append_int(self->parameters.names, "Center",
01181                                 LMP_CENT);
01182     cpl_propertylist_append_int(self->parameters.names, "Background",
01183                                 LMP_BACK);
01184     cpl_propertylist_append_int(self->parameters.names, "Width1",
01185                                 LMP_WID1);
01186 
01187     self->parameters.count =
01188         cpl_propertylist_get_size(self->parameters.names);
01189     self->parameters.values = cpl_matrix_new(self->parameters.count, 1);
01190 
01191     return;
01192 
01193 }
01194 
01195 
01196 inline static void
01197 _giraffe_gaussian_eval(cxdouble *y, cxdouble *x, cxdouble *a, cxint na,
01198                        cxdouble *dyda, cxdouble *r)
01199 {
01200 
01201     const cxchar *const fctid = "_giraffe_gaussian_eval";
01202 
01203 
01204     cxdouble fac;
01205     cxdouble ex;
01206     cxdouble amplitude;
01207     cxdouble center;
01208     cxdouble backg;
01209     cxdouble width;
01210     cxdouble xred;
01211 
01212 
01213     /* Not used */
01214     r = NULL;
01215 
01216     if (na != 4) {
01217         cpl_error_set(fctid, CPL_ERROR_ILLEGAL_INPUT);
01218         return;
01219     }
01220 
01221     *y = 0.0;
01222 
01223     if (dyda != NULL) {
01224         dyda[LMP_AMPL] = 0.;
01225         dyda[LMP_CENT] = 0.;
01226         dyda[LMP_BACK] = 0.;
01227         dyda[LMP_WID1] = 0.;
01228     }
01229 
01230 
01231     amplitude = a[LMP_AMPL];
01232     center    = a[LMP_CENT];
01233     backg     = a[LMP_BACK];
01234     width     = a[LMP_WID1];
01235 
01236     xred = (x[0] - center) / width;
01237 
01238     ex = exp(-xred * xred / 2.);
01239     fac = amplitude * xred * ex;
01240 
01241     *y = amplitude * ex + backg;
01242 
01243 
01244     /*
01245      * If requested, compute the partial derivatives of y
01246      * with respect to each parameter.
01247      */
01248 
01249     if (dyda != NULL) {
01250 
01251         dyda[LMP_AMPL] = ex;                      /* d(y)/d(amplitude) */
01252         dyda[LMP_CENT] = fac / width;             /* d(y)/d(center) */
01253         dyda[LMP_BACK] = 1.;                      /* d(y)/d(backg) */
01254         dyda[LMP_WID1] = (fac * xred) / width;    /* d(y)/d(width) */
01255 
01256     }
01257 
01258     return;
01259 
01260 }
01261 
01262 
01263 inline static void
01264 _giraffe_psfcos_ctor(GiModel *self, const GiModelData *model)
01265 {
01266 
01267     cx_assert(self != NULL);
01268     cx_assert(model != NULL);
01269 
01270     self->name = cx_strdup(model->name);
01271     self->type = model->type;
01272 
01273     self->model = model->eval;
01274 
01275 
01276     /*
01277      * Arguments
01278      */
01279 
01280     self->arguments.names = cpl_propertylist_new();
01281 
01282     cpl_propertylist_append_int(self->arguments.names, "x", 0);
01283 
01284     self->arguments.count = cpl_propertylist_get_size(self->arguments.names);
01285     self->arguments.values = cpl_matrix_new(self->arguments.count, 1);
01286 
01287 
01288     /*
01289      * Parameters
01290      */
01291 
01292     self->parameters.names = cpl_propertylist_new();
01293 
01294     cpl_propertylist_append_int(self->parameters.names, "Amplitude",
01295                                 LMP_AMPL);
01296     cpl_propertylist_append_int(self->parameters.names, "Center",
01297                                 LMP_CENT);
01298     cpl_propertylist_append_int(self->parameters.names, "Background",
01299                                 LMP_BACK);
01300     cpl_propertylist_append_int(self->parameters.names, "Width1",
01301                                 LMP_WID1);
01302     cpl_propertylist_append_int(self->parameters.names, "Width2",
01303                                 LMP_WID2);
01304 
01305     self->parameters.count =
01306         cpl_propertylist_get_size(self->parameters.names);
01307     self->parameters.values = cpl_matrix_new(self->parameters.count, 1);
01308 
01309     return;
01310 
01311 }
01312 
01313 
01314 inline static void
01315 _giraffe_psfcos_eval(cxdouble *y, cxdouble *x, cxdouble *a, cxint na,
01316                      cxdouble *dyda, cxdouble *r)
01317 {
01318 
01319     const cxchar *const fctid = "_giraffe_psfcos_eval";
01320 
01321 
01322     cxdouble amplitude;
01323     cxdouble center;
01324     cxdouble background;
01325     cxdouble width1;
01326     cxdouble width2;
01327 
01328     cxdouble t1, t2, t3, t4, t5, t6, t7, t8, t9;
01329     cxdouble t10, t13, t14, t15, t16;
01330     cxdouble t26;
01331 
01332 
01333     /* Not used */
01334     r = NULL;
01335 
01336     if (na != 5) {
01337         cpl_error_set(fctid, CPL_ERROR_ILLEGAL_INPUT);
01338         return;
01339     }
01340 
01341     *y = 0.0;
01342 
01343     if (dyda != NULL) {
01344         dyda[LMP_AMPL] = 0.;
01345         dyda[LMP_CENT] = 0.;
01346         dyda[LMP_BACK] = 0.;
01347         dyda[LMP_WID1] = 0.;
01348         dyda[LMP_WID2] = 0.;
01349     }
01350 
01351     amplitude  = a[LMP_AMPL];
01352     center     = a[LMP_CENT];
01353     background = a[LMP_BACK];
01354     width1     = a[LMP_WID1];
01355     width2     = a[LMP_WID2];
01356 
01357     t1 = x[0] - center;
01358     t2 = fabs(t1);
01359     t3 = 1.0 / width2;
01360     t4 = t2 * t3;
01361     t5 = pow(t4, width1);
01362     t6 = CX_PI * t5;
01363     t7 = cos(t6);
01364     t8 = 1.0 + t7;
01365     t9 = t8 * t8;
01366     t10 = t9 * t8;
01367     t13 = amplitude * t9;
01368     t14 = sin(t6);
01369     t15 = t13 * t14;
01370     t16 = log(t4);
01371     t26 = t1 > 0.0 ? 1.0 : -1.0;
01372 
01373     if (t2 > width2) {
01374         *y =  background;
01375 
01376         if (dyda != NULL) {
01377             dyda[LMP_WID2] = 1.0;
01378         }
01379     }
01380     else {
01381         *y = amplitude * t10 / 8.0 + background;
01382 
01383         if (dyda != NULL) {
01384 
01385             dyda[LMP_AMPL] = t10 / 8.0;
01386             dyda[LMP_CENT] = 3.0 / 8.0 * t13 * t14 * CX_PI * t5 *
01387                 width1 * t26 / t2;
01388             dyda[LMP_BACK] = 1.0;
01389             dyda[LMP_WID1] = -3.0 / 8.0 * t15 * t6 * t16;
01390             dyda[LMP_WID2] = 3.0 / 8.0 * t15 * t6 * width1 * t3;
01391 
01392         }
01393     }
01394 
01395     return;
01396 
01397 }
01398 
01399 
01400 inline static void
01401 _giraffe_psfexp_ctor(GiModel *self, const GiModelData *model)
01402 {
01403 
01404     cx_assert(self != NULL);
01405     cx_assert(model != NULL);
01406 
01407     self->name = cx_strdup(model->name);
01408     self->type = model->type;
01409 
01410     self->model = model->eval;
01411 
01412 
01413     /*
01414      * Arguments
01415      */
01416 
01417     self->arguments.names = cpl_propertylist_new();
01418 
01419     cpl_propertylist_append_int(self->arguments.names, "x", 0);
01420 
01421     self->arguments.count = cpl_propertylist_get_size(self->arguments.names);
01422     self->arguments.values = cpl_matrix_new(self->arguments.count, 1);
01423 
01424 
01425     /*
01426      * Parameters
01427      */
01428 
01429     self->parameters.names = cpl_propertylist_new();
01430 
01431     cpl_propertylist_append_int(self->parameters.names, "Amplitude",
01432                                 LMP_AMPL);
01433     cpl_propertylist_append_int(self->parameters.names, "Center",
01434                                 LMP_CENT);
01435     cpl_propertylist_append_int(self->parameters.names, "Background",
01436                                 LMP_BACK);
01437     cpl_propertylist_append_int(self->parameters.names, "Width1",
01438                                 LMP_WID1);
01439     cpl_propertylist_append_int(self->parameters.names, "Width2",
01440                                 LMP_WID2);
01441 
01442     self->parameters.count =
01443         cpl_propertylist_get_size(self->parameters.names);
01444     self->parameters.values = cpl_matrix_new(self->parameters.count, 1);
01445 
01446     return;
01447 
01448 }
01449 
01450 
01451 inline static void
01452 _giraffe_psfexp_eval(cxdouble *y, cxdouble *x, cxdouble *a, cxint na,
01453                      cxdouble *dyda, cxdouble *r)
01454 {
01455 
01456     const cxchar *const fctid = "_giraffe_psfexp_eval";
01457 
01458     cxdouble amplitude;
01459     cxdouble center;
01460     cxdouble background;
01461     cxdouble width1;
01462     cxdouble width2;
01463 
01464     cxdouble t1, t2, t3, t4, t6, t8;
01465     cxdouble t10, t15, t18;
01466 
01467 
01468     /* Not used */
01469     r = NULL;
01470 
01471     if (na != 5) {
01472         cpl_error_set(fctid, CPL_ERROR_ILLEGAL_INPUT);
01473         return;
01474     }
01475 
01476     *y = 0.0;
01477 
01478     if (dyda != NULL) {
01479         dyda[LMP_AMPL] = 0.;
01480         dyda[LMP_CENT] = 0.;
01481         dyda[LMP_BACK] = 0.;
01482         dyda[LMP_WID1] = 0.;
01483         dyda[LMP_WID2] = 0.;
01484     }
01485 
01486     amplitude  = a[LMP_AMPL];
01487     center     = a[LMP_CENT];
01488     background = a[LMP_BACK];
01489     width1     = a[LMP_WID1];
01490     width2     = a[LMP_WID2];
01491 
01492     t1 = x[0] - center;
01493 
01494     if (t1 > 0.0) {
01495         t2 = t1;
01496         t10 = 1.0;
01497     }
01498     else {
01499         t2 = -t1;
01500         t10 = -1.0;
01501     }
01502 
01503     t3 = pow(t2, width2);
01504     t4 = 1.0 / width1;
01505     t6 = exp(-t3 * t4);
01506     t8 = amplitude * t3;
01507     t15 = width1 * width1;
01508     t18 = log(t2);
01509 
01510     *y = amplitude * t6 + background;
01511 
01512     if (dyda != NULL) {
01513         dyda[LMP_AMPL] = t6;
01514         dyda[LMP_BACK] = 1.0;
01515 
01516         dyda[LMP_CENT] = t8 * width2 * t10 / t2 * t4 * t6;
01517 
01518         if (isnan(dyda[LMP_CENT])) {
01519             dyda[LMP_CENT] = 0.;
01520         }
01521 
01522         dyda[LMP_WID1] = t8 / t15 * t6;
01523 
01524         if (isnan(dyda[LMP_WID1])) {
01525             dyda[LMP_WID1] = 0.;
01526         }
01527 
01528         dyda[LMP_WID2] = -t8 * t18 * t4 * t6;
01529 
01530         if (isnan(dyda[LMP_WID2])) {
01531             dyda[LMP_WID2] = 0.;
01532         }
01533 
01534         if (r != NULL) {
01535 
01536             register cxint k;
01537 
01538             k = LMP_AMPL << 1;
01539             if (r[k + 1] > 0) {
01540                 dyda[LMP_AMPL] *= _giraffe_dydaweight(a[LMP_AMPL], r[k],
01541                                                       r[k + 1]);
01542             }
01543 
01544             k = LMP_CENT << 1;
01545             if (r[k + 1] > 0) {
01546                 dyda[LMP_CENT] *= _giraffe_dydaweight(a[LMP_CENT], r[k],
01547                                                       r[k + 1]);
01548             }
01549 
01550             k = LMP_WID1 << 1;
01551             if (r[k + 1] > 0) {
01552                 dyda[LMP_WID1] *= _giraffe_dydaweight(a[LMP_WID1], r[k],
01553                                                       r[k + 1]);
01554             }
01555 
01556             k = LMP_WID2 << 1;
01557             if (r[k + 1] > 0) {
01558                 dyda[LMP_WID2] *= _giraffe_dydaweight(a[LMP_WID2], r[k],
01559                                                       r[k + 1]);
01560             }
01561 
01562         }
01563 
01564     }
01565 
01566     return;
01567 
01568 }
01569 
01570 
01571 inline static void
01572 _giraffe_psfexp2_ctor(GiModel *self, const GiModelData *model)
01573 {
01574 
01575     cx_assert(self != NULL);
01576     cx_assert(model != NULL);
01577 
01578     self->name = cx_strdup(model->name);
01579     self->type = model->type;
01580 
01581     self->model = model->eval;
01582 
01583 
01584     /*
01585      * Arguments
01586      */
01587 
01588     self->arguments.names = cpl_propertylist_new();
01589 
01590     cpl_propertylist_append_int(self->arguments.names, "x", 0);
01591 
01592     self->arguments.count = cpl_propertylist_get_size(self->arguments.names);
01593     self->arguments.values = cpl_matrix_new(self->arguments.count, 1);
01594 
01595 
01596     /*
01597      * Parameters
01598      */
01599 
01600     self->parameters.names = cpl_propertylist_new();
01601 
01602     cpl_propertylist_append_int(self->parameters.names, "Amplitude",
01603                                 LMP_AMPL);
01604     cpl_propertylist_append_int(self->parameters.names, "Center",
01605                                 LMP_CENT);
01606     cpl_propertylist_append_int(self->parameters.names, "Background",
01607                                 LMP_BACK);
01608     cpl_propertylist_append_int(self->parameters.names, "Width1",
01609                                 LMP_WID1);
01610     cpl_propertylist_append_int(self->parameters.names, "Width2",
01611                                 LMP_WID2);
01612 
01613     self->parameters.count =
01614         cpl_propertylist_get_size(self->parameters.names);
01615     self->parameters.values = cpl_matrix_new(self->parameters.count, 1);
01616 
01617     return;
01618 
01619 }
01620 
01621 
01622 inline static void
01623 _giraffe_psfexp2_eval(cxdouble *y, cxdouble *x, cxdouble *a, cxint na,
01624                       cxdouble *dyda, cxdouble *r)
01625 {
01626 
01627     const cxchar *const fctid = "_giraffe_psfexp2_eval";
01628 
01629     cxdouble amplitude;
01630     cxdouble center;
01631     cxdouble background;
01632     cxdouble width1;
01633     cxdouble width2;
01634 
01635     cxdouble t1, t2, t3, t4, t5, t6, t8;
01636     cxdouble t10, t16;
01637 
01638 
01639     /* Not used */
01640     r = NULL;
01641 
01642     if (na != 5) {
01643         cpl_error_set(fctid, CPL_ERROR_ILLEGAL_INPUT);
01644         return;
01645     }
01646 
01647     *y = 0.0;
01648 
01649     if (dyda != NULL) {
01650         dyda[LMP_AMPL] = 0.;
01651         dyda[LMP_CENT] = 0.;
01652         dyda[LMP_BACK] = 0.;
01653         dyda[LMP_WID1] = 0.;
01654         dyda[LMP_WID2] = 0.;
01655     }
01656 
01657     amplitude  = a[LMP_AMPL];
01658     center     = a[LMP_CENT];
01659     background = a[LMP_BACK];
01660     width1     = a[LMP_WID1];
01661     width2     = a[LMP_WID2];
01662 
01663     t1 = x[0] - center;
01664 
01665     if (t1 > 0.0) {
01666         t2 = t1;
01667         t10 = 1.0;
01668     }
01669     else {
01670         t2 = -t1;
01671         t10 = -1.0;
01672     }
01673 
01674     t3 = 1.0 / width1;
01675     t4 = t2 * t3;
01676     t5 = pow(t4, width2);
01677     t6 = exp(-t5);
01678     t8 = amplitude * t5;
01679     t16 = log(t4);
01680 
01681     *y = amplitude * t6 + background;
01682 
01683     if (dyda != NULL) {
01684 
01685         dyda[LMP_AMPL] = t6;
01686 
01687         dyda[LMP_CENT] = t8 * width2 * t10 / t2 * t6;
01688 
01689         if (isnan(dyda[LMP_CENT])) {
01690             dyda[LMP_CENT] = 0.0;
01691         }
01692 
01693         dyda[LMP_BACK] = 1.0;
01694         dyda[LMP_WID1] = t8 * width2 * t3 * t6;
01695 
01696         dyda[LMP_WID2] = -t8 * t16 * t6;
01697 
01698         if (isnan(dyda[LMP_WID2])) {
01699             dyda[LMP_WID2] = 0.0;
01700         }
01701 
01702         if (r != NULL) {
01703 
01704             register cxint k;
01705 
01706             k = LMP_AMPL << 1;
01707             if (r[k + 1] > 0) {
01708                 dyda[LMP_AMPL] *= _giraffe_dydaweight(a[LMP_AMPL], r[k],
01709                                                       r[k + 1]);
01710             }
01711 
01712             k = LMP_CENT << 1;
01713             if (r[k + 1] > 0) {
01714                 dyda[LMP_CENT] *= _giraffe_dydaweight(a[LMP_CENT], r[k],
01715                                                       r[k + 1]);
01716             }
01717 
01718             k = LMP_WID1 << 1;
01719             if (r[k + 1] > 0) {
01720                 dyda[LMP_WID1] *= _giraffe_dydaweight(a[LMP_WID1], r[k],
01721                                                       r[k + 1]);
01722             }
01723 
01724             k = LMP_WID2 << 1;
01725             if (r[k + 1] > 0) {
01726                 dyda[LMP_WID2] *= _giraffe_dydaweight(a[LMP_WID2], r[k],
01727                                                       r[k + 1]);
01728             }
01729 
01730         }
01731 
01732     }
01733 
01734     return;
01735 
01736 }
01737 
01738 
01739 inline static void
01740 _giraffe_test_ctor(GiModel *self, const GiModelData *model)
01741 {
01742 
01743     cx_assert(self != NULL);
01744     cx_assert(model != NULL);
01745 
01746     self->name = cx_strdup(model->name);
01747     self->type = model->type;
01748 
01749     self->model = model->eval;
01750 
01751 
01752     /*
01753      * Arguments
01754      */
01755 
01756     self->arguments.names = cpl_propertylist_new();
01757 
01758     cpl_propertylist_append_int(self->arguments.names, "x", 0);
01759 
01760     self->arguments.count = cpl_propertylist_get_size(self->arguments.names);
01761     self->arguments.values = cpl_matrix_new(self->arguments.count, 1);
01762 
01763 
01764     /*
01765      * Parameters
01766      */
01767 
01768     self->parameters.names = cpl_propertylist_new();
01769 
01770     cpl_propertylist_append_int(self->parameters.names, "Slope", 0);
01771     cpl_propertylist_append_int(self->parameters.names, "Intercept", 1);
01772 
01773     self->parameters.count =
01774         cpl_propertylist_get_size(self->parameters.names);
01775     self->parameters.values = cpl_matrix_new(self->parameters.count, 1);
01776 
01777     return;
01778 
01779 }
01780 
01781 
01782 inline static void
01783 _giraffe_test_eval(cxdouble *y, cxdouble *x, cxdouble *a, cxint na,
01784                    cxdouble *dyda, cxdouble *r)
01785 {
01786 
01787     const cxchar *const fctid = "_giraffe_test_eval";
01788 
01789 
01790     cxdouble a1;
01791     cxdouble b1;
01792 
01793 
01794     /* Not used */
01795     r = NULL;
01796 
01797     if (na != 2) {
01798         cpl_error_set(fctid, CPL_ERROR_ILLEGAL_INPUT);
01799         return;
01800     }
01801 
01802     *y = 0.0;
01803 
01804     if (dyda != NULL) {
01805         dyda[0] = 0.;
01806         dyda[1] = 0.;
01807     }
01808 
01809     a1 = a[0];
01810     b1 = a[1];
01811 
01812     *y = a1 * x[0] + b1;
01813 
01814     if (dyda != NULL) {
01815 
01816         dyda[0] = x[0];
01817         dyda[1] = 0.0;
01818 
01819     }
01820 
01821     return;
01822 
01823 }
01824 
01825 
01826 /*
01827  * Model registry
01828  */
01829 
01830 static GiModelData _gimodels[] = {
01831     {"xoptmod", GI_MODEL_XOPT,
01832      _giraffe_xoptmod_ctor, _giraffe_model_dtor, _giraffe_xoptmod_eval},
01833     {"yoptmod", GI_MODEL_YOPT,
01834      _giraffe_yoptmod_ctor, _giraffe_model_dtor, _giraffe_yoptmod_eval},
01835     {"xoptmod2", GI_MODEL_XOPT,
01836      _giraffe_xoptmod2_ctor, _giraffe_model_dtor, _giraffe_xoptmod2_eval},
01837     {"yoptmod2", GI_MODEL_XOPT,
01838      _giraffe_yoptmod2_ctor, _giraffe_model_dtor, _giraffe_yoptmod2_eval},
01839     {"gaussian", GI_MODEL_LINE,
01840      _giraffe_gaussian_ctor, _giraffe_model_dtor, _giraffe_gaussian_eval},
01841     {"psfcos", GI_MODEL_LINE,
01842      _giraffe_psfcos_ctor, _giraffe_model_dtor, _giraffe_psfcos_eval},
01843     {"psfexp", GI_MODEL_LINE,
01844      _giraffe_psfexp_ctor, _giraffe_model_dtor, _giraffe_psfexp_eval},
01845     {"psfexp2", GI_MODEL_LINE,
01846      _giraffe_psfexp2_ctor, _giraffe_model_dtor, _giraffe_psfexp2_eval},
01847     {"test", GI_MODEL_LINE,
01848      _giraffe_test_ctor, _giraffe_model_dtor, _giraffe_test_eval},
01849     {NULL, 0, NULL, NULL, NULL}
01850 };

This file is part of the GIRAFFE Pipeline Reference Manual 2.9.0.
Documentation copyright © 2002-2006 European Southern Observatory.
Generated on Thu Jan 26 14:20:28 2012 by doxygen 1.6.3 written by Dimitri van Heesch, © 1997-2004