yanera_lstsq_constrained.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 #include "yanera.h"
00019 #include "yanera_lstsq_constrained.h"
00020 #include "yanera_quadrature.h"
00021 #include "yanera_reflectivity.h"
00022 #include "yanera_util.h"
00023 /*===========================================================================*/
00024 int yanera_lstsq_constrained_main(yanera_container *yanera)
00025 {
00026   unsigned int                        i;
00027   int                                 count, stop1, stop2;
00028   gsl_vector                         *guess;
00029   gsl_vector                         *gradt;
00030   gsl_matrix                         *covar;
00031   gsl_multifit_function_fdf           lstsq_func;
00032   gsl_multifit_fdfsolver             *solvr;
00033   
00034   /* Inital guess is the paramters as they were passed into here */
00035   guess = gsl_vector_alloc(yanera->parameters.n);
00036   for (i=0; i<yanera->parameters.n; i++) 
00037   {
00038     gsl_vector_set(guess, i, yanera->parameters.p[i]);
00039   }
00040 
00041   /* count the number of data points */
00042   count = 0;
00043   for (i=0; i<yanera->number_of_models; i++)
00044   {
00045     count += yanera->data[i].n;
00046   }
00047 
00048   /* need this vector for stop test #2 */
00049   gradt = gsl_vector_alloc(yanera->parameters.n);
00050   
00051   /* covariant matrix  */
00052   covar = gsl_matrix_alloc(yanera->parameters.n, yanera->parameters.n);
00053 
00054   lstsq_func.f      = &lstsq_f_constrained;
00055   lstsq_func.df     = &lstsq_df_constrained;
00056   lstsq_func.fdf    = &lstsq_fdf_constrained;
00057   lstsq_func.n      = count;                /* number of data points */
00058   lstsq_func.p      = yanera->parameters.n; /* number of paramters   */
00059   lstsq_func.params = (void *)yanera; /* pass the full yanera_container */
00060   
00061   solvr = gsl_multifit_fdfsolver_alloc(\
00062           yanera->misc.fit_method_lstsq, lstsq_func.n, lstsq_func.p);
00063 
00064   /*==================================================*/
00065   count = 0;
00066   gsl_multifit_fdfsolver_set(solvr, &lstsq_func, guess);
00067   gsl_multifit_covar(solvr->J, 0.0, covar);
00068   yanera_report(yanera, count, solvr);
00069 
00070   do
00071   { 
00072     count++;
00073     
00074     stop1 = gsl_multifit_fdfsolver_iterate(solvr);    
00075     gsl_multifit_covar(solvr->J, 0.0, covar);
00076     yanera_report(yanera, count, solvr);
00077     
00078     if (stop1) 
00079     {
00080       fprintf(stderr,"STATUS: %s\n", gsl_strerror(stop1));
00081       break;
00082     }
00083     
00084     /* Stop test #1 */
00085     stop1 = gsl_multifit_test_delta(solvr->dx, solvr->x, 1e-6, 1e-6);
00086 
00087     /* Stop test #2 */    
00088     gsl_multifit_gradient(solvr->J, solvr->f, gradt);
00089     stop2 = gsl_multifit_test_gradient(gradt, 1e-6);
00090     
00091     if ((stop1==GSL_SUCCESS) && (stop2==GSL_SUCCESS))
00092     {
00093       fprintf(stderr,"STATUS: %s\n", gsl_strerror(stop1));
00094     }
00095 
00096   } while (((stop1 == GSL_CONTINUE) || (stop2 == GSL_CONTINUE)) \
00097             && (count < yanera->misc.fit_iterations));
00098 
00099   /*==================================================*/
00100   gsl_multifit_covar(solvr->J, 0.0, covar);
00101   yanera_report(yanera, -1, solvr);
00102   
00103   /*==================================================*/
00104 
00105   gsl_multifit_fdfsolver_free(solvr);
00106   gsl_matrix_free(covar);
00107   gsl_vector_free(guess);
00108   gsl_vector_free(gradt);
00109 
00110   return GSL_SUCCESS;
00111 }
00112 /*===================================================================
00113  *    lstsq_fdf 
00114  */
00115 int lstsq_fdf_constrained(const gsl_vector *parameters, \
00116               void *yanera_pointer, \
00117               gsl_vector *r, gsl_matrix *J)
00118 {
00119   lstsq_f_constrained (parameters, yanera_pointer, r);
00120   lstsq_df_constrained(parameters, yanera_pointer, J);
00121   return GSL_SUCCESS;
00122 }
00123 /*===================================================================
00124  *    lstsq_f 
00125  */
00126 int lstsq_f_constrained(const gsl_vector *parameters, \
00127             void *yanera_pointer, \
00128             gsl_vector *r)
00129 {
00130   int                i, j;
00131   int                r_index;
00132   double             tmp;
00133   yanera_container  *yanera;
00134   /*
00135   ** r =>> residual
00136   */
00137   yanera = (yanera_container *)yanera_pointer;
00138   /*
00139   **  Load the params back into the parameter array.
00140   */
00141   for(i=0; i<yanera->parameters.n; i++)
00142   {
00143     yanera->parameters.p[i] = gsl_vector_get(parameters, i);
00144         
00145     if ((yanera->parameters.con[i] == CONSTRAIN_MAX) || \
00146         (yanera->parameters.con[i] == CONSTRAIN_BOTH))
00147     {
00148       if (yanera->parameters.p[i] > yanera->parameters.max[i])
00149       {
00150          yanera->parameters.p[i] = yanera->parameters.max[i];
00151       }
00152     }
00153     
00154     if ((yanera->parameters.con[i] == CONSTRAIN_MIN) || \
00155         (yanera->parameters.con[i] == CONSTRAIN_BOTH))
00156     {
00157       if (yanera->parameters.p[i] < yanera->parameters.min[i])
00158       {
00159          yanera->parameters.p[i] = yanera->parameters.min[i];
00160       }  
00161     }
00162   }
00163   /*
00164   ** Loop over the data sets and models
00165   */
00166   r_index = 0;
00167   for (j=0; j<yanera->number_of_models; j++)
00168   {
00169     /*
00170     ** Redo quadrature for this moel
00171     */
00172     if ((yanera->type == MODEL_COMPONENT) || \
00173         (yanera->type == MODEL_SLAB)      || \
00174         (yanera->type == MODEL_FUNCTION))
00175     { doQuadrature(&yanera->models_complete[j], yanera); }
00176     /*
00177     ** Loop over the data points
00178     */ 
00179     for (i=0; i<yanera->data[j].n; i++)
00180     {
00181       tmp = calcReflectivity(yanera->data[j].q[i], \
00182                              &yanera->data[j].resolution, \
00183                              &yanera->models_complete[j], \
00184                              yanera);
00185       tmp = (tmp - yanera->data[j].R[i]) / yanera->data[j].e[i];
00186       gsl_vector_set(r, r_index, tmp);
00187       r_index++; 
00188     }
00189     /*
00190     ** 
00191     */
00192   }
00193   
00194   return GSL_SUCCESS;
00195 }
00196 /*===================================================================
00197  *    lstsq_df 
00198  */
00199 int lstsq_df_constrained(const gsl_vector *parameters, \
00200              void *yanera_pointer, \
00201              gsl_matrix *J)
00202 {
00203   int                i, j, k;
00204   int                r_index;
00205   double             res, err;
00206   gsl_function       F;
00207   yanera_container  *yanera;
00208   /*
00209   **
00210   */
00211   yanera = (yanera_container *)yanera_pointer;
00212   /*
00213   **  Load the params into the temporary parameter array.
00214   */
00215   for(i=0; i<yanera->parameters.n; i++)
00216   {
00217     yanera->parameters.tmp[i] = gsl_vector_get(parameters, i);
00218         
00219     if ((yanera->parameters.con[i] == CONSTRAIN_MAX) || \
00220         (yanera->parameters.con[i] == CONSTRAIN_BOTH))
00221     {
00222       if (yanera->parameters.tmp[i] > yanera->parameters.max[i])
00223       {
00224         yanera->parameters.tmp[i] = yanera->parameters.max[i];
00225         /*
00226          * The addition of this line means that when a parameter hits a limit,
00227          * it will never move again.
00228          */
00229         yanera->parameters.f[i] = YES;
00230       }
00231     }
00232     
00233     if ((yanera->parameters.con[i] == CONSTRAIN_MIN) || \
00234         (yanera->parameters.con[i] == CONSTRAIN_BOTH))
00235     {
00236       if (yanera->parameters.tmp[i] < yanera->parameters.min[i])
00237       {
00238         yanera->parameters.tmp[i] = yanera->parameters.min[i];
00239         yanera->parameters.f[i] = YES;
00240       }
00241     }
00242   }
00243   /*
00244    *
00245    */
00246   F.function = &lstsq_derivatives_constrained;
00247   F.params   = yanera_pointer;
00248   /*
00249   ** Loop over the data sets
00250   */
00251   r_index = 0;
00252   for (k=0; k<yanera->number_of_models; k++)
00253   {
00254     /*
00255     **  The jacobian mtirx J_ij = d(r_i)/d(a_j)
00256     **  => i is the data index of residual r
00257     **  => j is the parameter index
00258     */
00259     yanera->idx = k;
00260     /*
00261     ** Loop over the data points
00262     */
00263     for (i=0; i<yanera->data[k].n; i++)
00264     {
00265       yanera->data[k].idx = i;
00266       /*
00267       ** Loop over the parameters 
00268       */
00269       for (j=0; j<yanera->parameters.n; j++) 
00270       {
00271         yanera->parameters.idx = j;
00272         /*
00273         ** If fixed, J_ij = 0
00274         */
00275         if (yanera->parameters.f[j] == YES) res=0.0;
00276         /*
00277          * This is commented out because of the change in the fixed
00278          * paramter status set above...
00279          * Now yanera->parameters.f[j] == YES for hitting a limit.
00280          *
00281         else if (yanera->parameters.tmp[j] ==  yanera->parameters.max[j]) 
00282         {
00283             res=0.0;
00284             yanera->parameters.p[j] =  yanera->parameters.max[j];
00285         }
00286         else if (yanera->parameters.tmp[j] ==  yanera->parameters.min[j]) 
00287         {
00288             res=0.0;
00289             yanera->parameters.p[j] =  yanera->parameters.min[j];
00290         }
00291         */
00292         else gsl_deriv_central(&F, yanera->parameters.tmp[j], 1e-5, &res, &err);
00293         gsl_matrix_set(J, r_index, j, res);
00294       }
00295       r_index++; 
00296     }
00297     /*
00298     **  Where do we gaurantee that for each model there is a datafile?
00299     */
00300   }
00301     
00302   return GSL_SUCCESS;
00303 }
00304 /*===================================================================
00305  *    lstsq_derivatives 
00306  */
00307 double lstsq_derivatives_constrained(double new_p, void *yanera_pointer)
00308 {
00309   int                i;
00310   double             tmp;
00311   yanera_container  *yanera;
00312   /*
00313   ** p =>> varying parameter for derivative
00314   */
00315   yanera = (yanera_container  *)yanera_pointer; 
00316   /*
00317    *  We need move the parameters from 'tmp', back into 'p'
00318    *  with the derivative parameter 'new_p' 
00319    *  replacing the parameter at index 'y->parameters.idx'.
00320    *
00321    *  model and data index  = yanera->idx;
00322    *  parameter index       = yanera->parameters.idx;
00323    *  data point index      = yanera->data[yanera->idx].idx;
00324    */
00325   for(i=0; i<yanera->parameters.n; i++) 
00326   {
00327     yanera->parameters.p[i] = yanera->parameters.tmp[i];
00328   }
00329   yanera->parameters.p[yanera->parameters.idx] = new_p;
00330   if ((yanera->type == MODEL_COMPONENT) || \
00331       (yanera->type == MODEL_SLAB)      || \
00332       (yanera->type == MODEL_FUNCTION))
00333   { doQuadrature(&yanera->models_complete[yanera->idx], yanera); }
00334   
00335   tmp = 0.0;
00336   i = yanera->data[yanera->idx].idx;
00337   tmp = calcReflectivity(yanera->data[yanera->idx].q[i], \
00338                         &yanera->data[yanera->idx].resolution, \
00339                         &yanera->models_complete[yanera->idx], \
00340                          yanera);
00341   tmp = (tmp - yanera->data[yanera->idx].R[i]) /  \
00342                yanera->data[yanera->idx].e[i];
00343   return tmp;
00344 }
00345 

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