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