File indexing completed on 2025-01-05 04:13:02

0001 /***************************************************************************
0002  *                                                                         *
0003  *   copyright : (C) 2007 The University of Toronto                        *
0004  *                   netterfield@astro.utoronto.ca                         *
0005  *                                                                         *
0006  *   This program is free software; you can redistribute it and/or modify  *
0007  *   it under the terms of the GNU General Public License as published by  *
0008  *   the Free Software Foundation; either version 2 of the License, or     *
0009  *   (at your option) any later version.                                   *
0010  *                                                                         *
0011  ***************************************************************************/
0012 
0013 #ifndef NON_LINEAR_H
0014 #define NON_LINEAR_H
0015 
0016 #include <stdlib.h>
0017 #include <string.h>
0018 #include <math.h>
0019 #include <gsl/gsl_rng.h>
0020 #include <gsl/gsl_vector.h>
0021 #include <gsl/gsl_blas.h>
0022 #include <gsl/gsl_multifit_nlin.h>
0023 #include <gsl/gsl_statistics.h>
0024 #include <gsl/gsl_version.h>
0025 #include "common.h"
0026 
0027 struct data {
0028   int   n;
0029   const double* pdX;
0030   const double* pdY;
0031 };
0032 
0033 int n_params = NUM_PARAMS;
0034 double offset_ = 0.0;
0035 
0036 void function_initial_estimate( const double* pdX, const double* pdY, int iLength, double* pdParameterEstimates );
0037 double function_calculate( double dX, double* pdParameters );
0038 void function_derivative( double dX, double* pdParameters, double* pdDerivatives );
0039 int function_f( const gsl_vector* pVectorX, void* pParams, gsl_vector* pVectorF );
0040 int function_df( const gsl_vector* pVectorX, void* pParams, gsl_matrix* pMatrixJ );
0041 int function_fdf( const gsl_vector* pVectorX, void* pParams, gsl_vector* pVectorF, gsl_matrix* pMatrixJ );
0042 bool kstfit_nonlinear(
0043   Kst::VectorPtr xVector, Kst::VectorPtr yVector,
0044   Kst::VectorPtr vectorOutYFitted, Kst::VectorPtr vectorOutYResiduals,
0045   Kst::VectorPtr vectorOutYParameters, Kst::VectorPtr vectorOutYCovariance,
0046   Kst::ScalarPtr scalarOutChi );
0047 
0048 
0049 int function_f( const gsl_vector* pVectorX, void* pParams, gsl_vector* pVectorF ) {
0050   double    dParameters[NUM_PARAMS];
0051   double    dY;
0052   data*     pData   = (data*)pParams;
0053   int       i;
0054 
0055   for( i=0; i<n_params; i++ ) {
0056     dParameters[i] = gsl_vector_get( pVectorX, i );
0057   }
0058 
0059   for( i=0; i<pData->n; i++ ) {
0060     dY  = function_calculate( pData->pdX[i], dParameters );
0061     gsl_vector_set( pVectorF, i, dY - pData->pdY[i] );
0062   }
0063 
0064   return GSL_SUCCESS;
0065 }
0066 
0067 
0068 int function_df( const gsl_vector* pVectorX, void* pParams, gsl_matrix* pMatrixJ ) {
0069   double dParameters[NUM_PARAMS];
0070   double dDerivatives[NUM_PARAMS];
0071   data*  pData  = (data*)pParams;
0072   int i;
0073   int j;
0074 
0075   for( i=0; i<n_params; i++ ) {
0076     dParameters[i] = gsl_vector_get( pVectorX, i );
0077   }
0078 
0079   for( i=0; i<pData->n; i++ ) {
0080     function_derivative( pData->pdX[i], dParameters, dDerivatives );
0081 
0082     for( j=0; j<n_params; j++ ) {
0083       gsl_matrix_set( pMatrixJ, i, j, dDerivatives[j] );
0084     }
0085   }
0086 
0087   return GSL_SUCCESS;
0088 }
0089 
0090 
0091 int function_fdf( const gsl_vector* pVectorX, void* pParams, gsl_vector* pVectorF, gsl_matrix* pMatrixJ ) {  
0092   function_f( pVectorX, pParams, pVectorF );
0093   function_df( pVectorX, pParams, pMatrixJ );
0094 
0095   return GSL_SUCCESS;
0096 }
0097 
0098 
0099 bool kstfit_nonlinear(
0100   Kst::VectorPtr xVector, Kst::VectorPtr yVector,
0101   Kst::VectorPtr vectorOutYFitted, Kst::VectorPtr vectorOutYResiduals,
0102   Kst::VectorPtr vectorOutYParameters, Kst::VectorPtr vectorOutYCovariance,
0103   Kst::ScalarPtr scalarOutChi ) {
0104 
0105   const gsl_multifit_fdfsolver_type* pType;
0106   gsl_multifit_fdfsolver* pSolver;
0107   gsl_multifit_function_fdf function;
0108   gsl_vector_view vectorViewInitial;
0109   gsl_matrix* pMatrixCovariance;
0110   gsl_matrix *pMatrixJacobian;
0111   struct data d;  
0112   double dXInitial[NUM_PARAMS];
0113   double* pInputX;
0114   double* pInputY;
0115   int iIterations = 0;
0116   int iLength;
0117   bool bReturn = false;
0118   int iStatus;
0119   int i;
0120   int j;
0121 
0122   if (xVector->length() >= 2 &&
0123       yVector->length() >= 2 ) {
0124     iLength = yVector->length();
0125     if( xVector->length() > iLength ) {
0126       iLength = xVector->length();
0127     }
0128 
0129     pInputX = (double*)malloc(iLength * sizeof( double ));
0130 
0131     double const *v_x = xVector->noNanValue();
0132     double const *v_y = yVector->noNanValue();
0133 
0134     if (xVector->length() == iLength) {
0135       for( i=0; i<iLength; i++) {
0136         pInputX[i] = v_x[i];
0137       }
0138     } else {
0139       for( i=0; i<iLength; i++) {
0140         pInputX[i] = interpolate( i, iLength, v_x, xVector->length() );
0141       }
0142     }
0143 
0144     pInputY = (double*)malloc(iLength * sizeof( double ));
0145     if (yVector->length() == iLength) {
0146       for( i=0; i<iLength; i++) {
0147         pInputY[i] = v_y[i];
0148       }
0149     } else {
0150       for( i=0; i<iLength; i++) {
0151         pInputY[i] = interpolate( i, iLength, v_y, yVector->length() );
0152       }
0153     }
0154 
0155     if( iLength > NUM_PARAMS ) {
0156       vectorOutYFitted->resize(iLength);
0157       vectorOutYResiduals->resize(iLength);
0158       vectorOutYParameters->resize(NUM_PARAMS);
0159       vectorOutYCovariance->resize(NUM_PARAMS * NUM_PARAMS);
0160 
0161       pType   = gsl_multifit_fdfsolver_lmsder;
0162       pSolver = gsl_multifit_fdfsolver_alloc( pType, iLength, n_params );
0163       if( pSolver != NULL ) {
0164         d.n      = iLength;
0165         d.pdX      = pInputX;
0166         d.pdY    = pInputY;
0167 
0168         function.f        = function_f;
0169         function.df       = function_df;
0170         function.fdf      = function_fdf;
0171         function.n        = iLength;
0172         function.p        = n_params;
0173         function.params = &d;
0174 
0175         pMatrixCovariance = gsl_matrix_alloc( n_params, n_params );
0176         if( pMatrixCovariance != NULL ) {
0177           function_initial_estimate( pInputX, pInputY, iLength, dXInitial );
0178           vectorViewInitial = gsl_vector_view_array( dXInitial, n_params );
0179 
0180           gsl_multifit_fdfsolver_set( pSolver, &function, &vectorViewInitial.vector );
0181 
0182           //
0183           // iterate to a solution...
0184           //
0185           do {
0186             iStatus = gsl_multifit_fdfsolver_iterate( pSolver );
0187             if( iStatus == GSL_SUCCESS ) {
0188               iStatus = gsl_multifit_test_delta( pSolver->dx, pSolver->x, 1.0e-6, 1.0e-6 );
0189             }
0190             iIterations++;
0191           } while( iStatus == GSL_CONTINUE && iIterations < MAX_NUM_ITERATIONS );
0192 #if GSL_MAJOR_VERSION >= 2
0193           pMatrixJacobian = gsl_matrix_alloc( iLength, n_params );
0194 #else
0195           pMatrixJacobian = pSolver->J;
0196 #endif
0197           if ( pMatrixJacobian != NULL) {
0198 #if GSL_MAJOR_VERSION >= 2
0199             gsl_multifit_fdfsolver_jac( pSolver, pMatrixJacobian );
0200 #endif
0201             gsl_multifit_covar( pMatrixJacobian, 0.0, pMatrixCovariance );
0202 
0203             //
0204             // determine the fitted values...
0205             //
0206             for( i=0; i<n_params; i++ ) {
0207               dXInitial[i] = gsl_vector_get( pSolver->x, i );
0208             }
0209 
0210             for( i=0; i<iLength; i++ ) {
0211               vectorOutYFitted->raw_V_ptr()[i] = function_calculate( pInputX[i], dXInitial );
0212               vectorOutYResiduals->raw_V_ptr()[i] = pInputY[i] - vectorOutYFitted->raw_V_ptr()[i];
0213             }
0214 
0215             //
0216             // fill in the parameter values and covariance matrix...
0217             //
0218             for( i=0; i<NUM_PARAMS; i++ ) {
0219               if (i<n_params) {
0220                 vectorOutYParameters->raw_V_ptr()[i] = gsl_vector_get( pSolver->x, i );
0221               } else {
0222                 vectorOutYParameters->raw_V_ptr()[i] = offset_;
0223               }
0224               for( j=0; j<NUM_PARAMS; j++ ) {
0225                 if ((i<n_params) && (j<n_params)) {
0226                   vectorOutYCovariance->raw_V_ptr()[(i*n_params)+j] = gsl_matrix_get( pMatrixCovariance, i, j );
0227                 } else {
0228                   vectorOutYCovariance->raw_V_ptr()[(i*n_params)+j] = 0.0;
0229                 }
0230               }
0231             }
0232 
0233             //
0234             // determine the value of chi^2/nu
0235             //
0236             scalarOutChi->setValue(gsl_blas_dnrm2( pSolver->f ));
0237 
0238             bReturn = true;
0239             
0240 #if GSL_MAJOR_VERSION >= 2
0241             gsl_matrix_free( pMatrixJacobian );
0242 #endif
0243           }
0244           gsl_matrix_free( pMatrixCovariance );
0245         }
0246         gsl_multifit_fdfsolver_free( pSolver );
0247       }
0248     }
0249     free( pInputX );
0250     free( pInputY );
0251   }
0252 
0253   return bReturn;
0254 }
0255 
0256 #endif