yanera_levmar.c

Go to the documentation of this file.
00001 /*============================================================================
00002 Copyright 2006 Thad Harroun, Kevin Yager
00003 
00004 This file is part of "yanera 2.0".
00005 
00006 "yanera 2.0" is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
00007 
00008 "yanera 2.0" is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
00009 
00010 You should have received a copy of the GNU General Public License along with "yanera 2.0"; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 
00011 =============================================================================*/
00018 #ifdef HAVE_LEVMAR
00019 
00020 #include "yanera.h"
00021 #include "lm.h"
00022 #include "yanera_levmar.h"
00023 #include "yanera_quadrature.h"
00024 #include "yanera_reflectivity.h"
00025 #include "yanera_util.h"
00026 /* ========================================================================== */
00027 void levmar_f( double *p, double *y, int np, int ny, void *yanera_pointer)
00028 {
00029   int                i, j;
00030   int                y_index;
00031   double             tmp;
00032   yanera_container  *yanera;
00033   /*
00034   ** 
00035   */
00036   yanera = (yanera_container *)yanera_pointer;
00037   /*
00038   **  Load the params back into the parameter array.
00039   */
00040   if (yanera->parameters.n != np) 
00041   {
00042     yanera_error("Error in levmar.", __FILE__, __LINE__, yanera);
00043   }
00044   
00045   for(i=0; i<yanera->parameters.n; i++)
00046   {
00047     yanera->parameters.p[i] = p[i];
00048   }
00049   /*
00050   ** Loop over the data sets and models
00051   */
00052   y_index = 0;
00053   for (j=0; j<yanera->number_of_models; j++)
00054   {
00055     /*
00056     ** Redo quadrature for these model types
00057     */
00058     if ((yanera->type == MODEL_COMPONENT) || \
00059         (yanera->type == MODEL_SLAB)      || \
00060         (yanera->type == MODEL_FUNCTION))
00061     { doQuadrature(&yanera->models_complete[j], yanera); }
00062     /*
00063     ** Loop over the data points
00064     */ 
00065     for (i=0; i<yanera->data[j].n; i++)
00066     {
00067       tmp = calcReflectivity(yanera->data[j].q[i], \
00068                              &yanera->data[j].resolution, \
00069                              &yanera->models_complete[j], \
00070                              yanera);
00071       tmp = tmp / yanera->data[j].e[i];
00072       y[y_index] = tmp;
00073       y_index++; 
00074       if (y_index > ny) 
00075       {
00076         yanera_error("Error in levmar.", __FILE__, __LINE__, yanera);
00077       }
00078     }
00079     /*
00080     ** 
00081     */
00082   }
00083   
00084   return;
00085 }
00086 /* ========================================================================== */
00087 double levmar_derivatives(double new_p, void *yanera_pointer)
00088 {
00089   int                i;
00090   double             tmp;
00091   yanera_container  *yanera;
00092   /*
00093   ** p =>> varying parameter for derivative
00094   */
00095   yanera = (yanera_container  *)yanera_pointer; 
00096   /*
00097    *  We need move the parameters from 'tmp', back into 'p'
00098    *  with the derivative parameter 'new_p' 
00099    *  replacing the parameter at index 'y->parameters.idx'.
00100    *
00101    *  model and data index  = yanera->idx;
00102    *  parameter index       = yanera->parameters.idx;
00103    *  data point index      = yanera->data[yanera->idx].idx;
00104    */
00105   for(i=0; i<yanera->parameters.n; i++) 
00106   {
00107     yanera->parameters.p[i] = yanera->parameters.tmp[i];
00108   }
00109   yanera->parameters.p[yanera->parameters.idx] = new_p;
00110   if ((yanera->type == MODEL_COMPONENT) || \
00111       (yanera->type == MODEL_SLAB)      || \
00112       (yanera->type == MODEL_FUNCTION))
00113   { doQuadrature(&yanera->models_complete[yanera->idx], yanera); }
00114   
00115   tmp = 0.0;
00116   i = yanera->data[yanera->idx].idx;
00117   tmp = calcReflectivity(yanera->data[yanera->idx].q[i], \
00118                         &yanera->data[yanera->idx].resolution, \
00119                         &yanera->models_complete[yanera->idx], \
00120                          yanera);
00121   tmp = tmp / yanera->data[yanera->idx].e[i];
00122   
00123   return tmp;
00124 }
00125 /* ========================================================================== */
00126 void levmar_df(double *p, double *j, int np, int ny, void *yanera_pointer)
00127 {
00128   static short       iter = 0;
00129   int                i, l, k;
00130   int                j_index;
00131   double             res, err;
00132   gsl_function       F;
00133   yanera_container  *yanera;
00134   /*
00135    * Assuming 1 iteration is equal to 1 jacobian evaluation, call
00136    * yanera_report from here
00137    */
00138   yanera = (yanera_container *)yanera_pointer;
00139   yanera_report(yanera, iter++, NULL);
00140   /*
00141    *  Load the params into the temporary parameter array.
00142    */
00143   if (yanera->parameters.n != np)
00144   {
00145     yanera_error("Error in levmar.", __FILE__, __LINE__, yanera);
00146   }
00147   for(i=0; i<yanera->parameters.n; i++)
00148   {
00149     yanera->parameters.tmp[i] = p[i];
00150   }
00151   /*
00152    * Functions for gsl_deriv_central
00153    */
00154   F.function = &levmar_derivatives;
00155   F.params   = yanera_pointer;
00156   /*
00157    * Loop over the data sets
00158    */
00159   j_index = 0;
00160   for (k=0; k<yanera->number_of_models; k++)
00161   {
00162     /*
00163     **  The jacobian mtirx J_il = d(f_i)/d(a_l)
00164     **  => i is the data index of f
00165     **  => l is the parameter index
00166     */
00167     yanera->idx = k;
00168     /*
00169     ** Loop over the data points
00170     */
00171     for (i=0; i<yanera->data[k].n; i++)
00172     {
00173       yanera->data[k].idx = i;
00174       /*
00175       ** Loop over the parameters 
00176       */
00177       for (l=0; l<yanera->parameters.n; l++) 
00178       {
00179         yanera->parameters.idx = l;
00180         /*
00181         ** If fixed, J_ij = 0
00182         */
00183         if (yanera->parameters.f[l] == YES) res=0.0;
00184         else gsl_deriv_central(&F, yanera->parameters.tmp[l], 1e-5, &res, &err);
00185         j[j_index] = res;
00186         j_index++;
00187       }
00188     }
00189   }
00190     
00191   return;
00192 }
00193 /* ========================================================================== */
00194 int yanera_levmar_main(yanera_container *yanera)
00195 {
00196   int           i, j, count;
00197   double        opts[4], info[LM_INFO_SZ];
00198   double        tmp, *y, *p, *work;
00199 
00200 
00201   /*
00202    * Levmar expects a single vector of all the data.
00203    * I have no idea what option \mu is, but LEVMAR works well
00204    * by calculating the smallest data point times error = tmp. 
00205    */
00206   count = 0;
00207   for (i=0; i<yanera->number_of_models; i++)
00208   { count += yanera->data[i].n; }
00209   y = (double *)malloc(count*sizeof(double));
00210   if (y == NULL)
00211   {
00212     yanera_error("Error in levmar.", __FILE__, __LINE__, yanera);
00213   }
00214   count = 0;
00215   tmp = 10000.5;
00216   for (i=0; i<yanera->number_of_models; i++)
00217   {
00218     for (j=0; j<yanera->data[i].n; j++)
00219     {
00220       y[count] = yanera->data[i].R[j] / yanera->data[i].e[j];
00221       if (tmp > yanera->data[i].R[j] * yanera->data[i].e[j])
00222       {
00223         tmp = yanera->data[i].R[j] * yanera->data[i].e[j];
00224       }
00225       count++; 
00226     }
00227   }
00228   /*
00229    * Vector p is the starting guess, and is also used as workspace,
00230    * so it was a mistake before to just pass yanera->parameters.p
00231    * as the inital guess.
00232    */
00233   p = (double *)malloc(yanera->parameters.n*sizeof(double));
00234   for (i=0; i<yanera->parameters.n; i++)
00235   {
00236     p[i] = yanera->parameters.p[i];
00237   }
00238   /*
00239    * Some user settable options. See the Levmar web page for what
00240    * they are. I don't know if setting opts[0] really helps or not.
00241    */
00242   opts[0] = tmp*10.0;
00243   opts[1] = 1E-8;
00244   opts[2] = 1E-8;
00245   opts[3] = 1E-8;
00246   /*
00247    *  Workspace provided to Levmar.
00248    */
00249   work = (double *)malloc(LM_DIF_WORKSZ(yanera->parameters.n,count)* \
00250                           sizeof(double));
00251   if (work == NULL)
00252   {
00253     yanera_error("Error in levmar.", __FILE__, __LINE__, yanera);
00254   }
00255   
00256   /*
00257    * Levmar routine. Returns number of iterations = jacobian evaluations
00258    * as far as I can tell.
00259    * Not sure how to get modulous for reporting.
00260    */
00261   tmp = dlevmar_bc_der(levmar_f, levmar_df,                            \
00262                        p, y,                        \
00263                        yanera->parameters.n, count,                    \
00264                        yanera->parameters.min, yanera->parameters.max, \
00265                        yanera->misc.fit_iterations, opts, info, \
00266                        work, NULL, (void *)yanera);
00267   /*
00268    * Get the answers to the fit and report completed.
00269    */                  
00270   for (i=0; i<yanera->parameters.n; i++)
00271   {
00272     yanera->parameters.p[i] = p[i];
00273   }
00274   yanera_report(yanera, -1, NULL);
00275   /*
00276    * Optional information
00277   fprintf(stderr, "RET:%g\n", tmp);
00278   fprintf(stderr, "I 0:%g\n", info[0]);
00279   fprintf(stderr, "I 1:%g\n", info[1]);
00280   fprintf(stderr, "I 2:%g\n", info[2]);
00281   fprintf(stderr, "I 3:%g\n", info[3]);
00282   fprintf(stderr, "I 4:%g\n", info[4]);
00283   fprintf(stderr, "I 5:%g\n", info[5]);
00284   fprintf(stderr, "I 6:%g\n", info[6]);
00285   fprintf(stderr, "I 7:%g\n", info[7]);
00286   fprintf(stderr, "I 8:%g\n", info[8]);
00287   fprintf(stderr, "c  :%d\n", count);
00288   fprintf(stderr, "n  :%d\n", yanera->parameters.n);
00289   */
00290   
00291   free(p);
00292   free(y);
00293   free(work);
00294   
00295   return (GSL_SUCCESS);
00296 }
00297 
00298 #endif

Generated on Thu May 29 10:56:33 2008 by  doxygen 1.5.5