libSUFR
a LIBrary of Some Useful Fortran Routines
All Classes Namespaces Files Functions Variables Pages
fitting.f90
Go to the documentation of this file.
1!> \file fitting.f90 Procedures to fit functions to data
2
3
4! Copyright (c) 2002-2025 Marc van der Sluys - Nikhef/Utrecht University - marc.vandersluys.nl
5!
6! This file is part of the libSUFR package,
7! see: http://libsufr.sourceforge.net/
8!
9! This is free software: you can redistribute it and/or modify it under the terms of the European Union
10! Public Licence 1.2 (EUPL 1.2). This software is distributed in the hope that it will be useful, but
11! WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12! PURPOSE. See the EU Public Licence for more details. You should have received a copy of the European
13! Union Public Licence along with this code. If not, see <https://www.eupl.eu/1.2/en/>.
14!
15!
16
17
18
19
20!***********************************************************************************************************************************
21!> \brief Procedures to fit functions to data
22
24 implicit none
25 save
26
27 private
28
30
31contains
32
33 !*********************************************************************************************************************************
34 !> \brief Fit the model coefficients using a chi^2 method
35 !!
36 !! Do a chi^2-minimisation fit of nDat data points xDat and yDat, the latter with errors yErr, to function func. The fit uses
37 !! the nCoef coefficients stored in fCoef() that should be varied if the corresponding entry in freeCoef=1, fixed if =0.
38 !!
39 !! The fitting function must be provided as the subroutine myFunc which returns a value y = myFunc(x, basefunc, nCoef), where
40 !! y is a linear combination of x, i.e. y = SUM(i=1,nCoef) fCoef(i) * basefunc(i)(x).
41 !! For example, for a polynomial, basefunc(i) = x**(i-1).
42 !!
43 !! The routine returns the fit coefficients in fCoef(), the variance-covariance matrix in covMat sith size nCov, and the chi^2
44 !! value in chiSq.
45 !!
46 !!
47 !! \param nDat Number of data points
48 !! \param xDat X values of the data (nDat)
49 !! \param yDat Y values of the data (nDat)
50 !! \param yErr Errors (standard deviations) of the y values (nDat)
51 !!
52 !! \param nCoef Number of coefficients of the fitting function
53 !! \param fCoef Coefficients of the fitting function (nCoef) (output)
54 !! \param freeCoef Fix coefficient coef(i) if freeCoef(i)=0, otherwise let if vary freely and fit it (nCoef)
55 !!
56 !! \param nCov Size of both dimensions of covMat()
57 !! \param covMat Covariance matrix (nCov,nCov) (output)
58 !!
59 !! \param chiSq Chi^2 - chi squared (output)
60 !!
61 !! \param myFunc External subroutine that describes the model value of Y for given value X
62 !!
63 !! \note
64 !! - Needs sort_var_covar_matrix() and solve_linear_equations_Gauss_Jordan()
65 !!
66 !! \see Numerical Recipes in Fortran 77, Sect.15.4
67 !!
68
69 subroutine linear_fit_yerr(nDat, xDat,yDat, yErr, nCoef,fCoef,freeCoef, nCov,covMat, chiSq, myFunc)
70 use sufr_kinds, only: double
72 implicit none
73 integer, parameter :: mmax = 50
74 integer, intent(in) :: ndat, ncoef,freecoef(ncoef), ncov
75 real(double), intent(in) :: xdat(ndat),ydat(ndat), yerr(ndat)
76 real(double), intent(inout) :: fcoef(ncoef)
77 real(double), intent(out) :: chisq, covmat(ncov,ncov)
78
79 integer :: ii,ij,ik,il,im, nfit
80 real(double) :: err2i,bf_e2i, tot,ym, basefunc(mmax),beta(mmax)
81 external myfunc
82
83 if(minval(abs(yerr)).lt.10*tiny(yerr)) call quit_program_error('libSUFR linear_fit_yerr(): errors cannot be zero', 0)
84
85 ! Determine number of parameters that need to be fit:
86 nfit = 0
87 do ij=1,ncoef
88 if(freecoef(ij).ne.0) nfit = nfit+1
89 end do
90 if(nfit.eq.0) call warn('libSUFR linear_fit_yerr(): No parameters to be fit for', 0)
91
92 covmat(1:nfit,1:nfit) = 0.d0
93 beta(1:nfit) = 0.d0
94
95 do ii=1,ndat
96 call myfunc(xdat(ii),ncoef, basefunc)
97 ym = ydat(ii)
98 if(nfit.lt.ncoef) then
99 do ij=1,ncoef
100 if(freecoef(ij).eq.0) ym = ym - fcoef(ij)*basefunc(ij)
101 end do
102 end if
103 err2i = 1.d0/yerr(ii)**2 ! 1/sigma_i^2
104
105 ij = 0
106 do il=1,ncoef
107 if(freecoef(il).ne.0) then
108 ij = ij + 1
109 bf_e2i = basefunc(il)*err2i
110
111 ik = 0
112 do im=1,il
113 if(freecoef(im).ne.0) then
114 ik = ik + 1
115 covmat(ij,ik) = covmat(ij,ik) + bf_e2i*basefunc(im)
116 end if
117 end do
118 beta(ij) = beta(ij) + ym*bf_e2i
119 end if
120 end do
121 end do
122
123 do ij=2,nfit
124 do ik=1,ij-1
125 covmat(ik,ij) = covmat(ij,ik)
126 end do
127 end do
128
129 ! Solve the linear algebraic equations using Gauss-Jordan elimination:
130 call solve_linear_equations_gauss_jordan(nfit, ncov,covmat, 1, 1,beta)
131
132 ij = 0
133 do il=1,ncoef
134 if(freecoef(il).ne.0) then
135 ij = ij+1
136 fcoef(il) = beta(ij)
137 end if
138 end do
139
140 chisq = 0.d0
141 do ii=1,ndat
142 call myfunc(xdat(ii),ncoef, basefunc)
143
144 tot = sum(fcoef(1:ncoef)*basefunc(1:ncoef))
145 chisq = chisq + ( (ydat(ii)-tot) / yerr(ii) )**2
146 end do
147
148 ! Sort the resulting variance-covariance matrix:
149 call sort_var_covar_matrix(ncov,covmat, ncoef,freecoef, nfit)
150
151 end subroutine linear_fit_yerr
152 !*********************************************************************************************************************************
153
154
155
156
157 !*********************************************************************************************************************************
158 !> \brief Levenberg-Marquardt method to reduce the value of chi-squared of a fit of a set of data points with errors in Y to a
159 !! non-linear function
160 !!
161 !! You will need to call this routine repeatedly, with different values for iterStat, until chiSq no longer decreases
162 !! (significantly)
163 !!
164 !! \param nY Number of Y values for each X value (normally 1, but e.g. 2 for a sky position with two coordinates)
165 !! \param nDat Number of data points in X and Y
166 !!
167 !! \param xDat X data points to fit
168 !! \param yDat Y data points to fit
169 !! \param yErr Errors (standard deviations) for yDat
170 !!
171 !! \param nCoef Number of coefficients used to describe the non-linear function myFunc
172 !! \param fCoef Coefficients for the non-linear function myFunc, updated after each call
173 !! \param freeCoef Determines which coefficients for the non-linear function myFunc should be fitted for. Set freeCoef(i) = 0
174 !! in order to keep fCoef(i) fixed
175 !!
176 !! \param nMat Size of the matrices; > nCoef
177 !! \param covMat Variance-covariance matrix - returned on last call with iterStat. Fixed parameters return zero (co)variances
178 !! \param curvMat Hessian/curvature matrix - double partial derivative of chi squared to two coefficients fCoef
179 !!
180 !! \param chiSq Chi squared
181 !! \param iterStat Iteration status; Set to <0 for initialisation in the first call, and let it vary in subsequent calls,
182 !! until the fit converges. After that, set to 0 to return the variance-covariance and curvature matrices
183 !! on the final call. IterStat decreases 10x if chiSq becomes smaller, and increases 10x otherwise.
184 !! \param myFunc External subroutine that describes the model value of Y and partial derivatives dY/dXi for given value X and
185 !! function coefficients fCoef
186 !!
187 !! \see Numerical Recipes in Fortran, 15.5: Modelling of Data / Non-linear models
188 !!
189 !! \note Uses sort_var_covar_matrix(), solve_linear_equations_Gauss_Jordan() and nonlin_fit_eval()
190
191 subroutine nonlin_fit_yerr(nY,nDat, xDat,yDat, yErr, nCoef,fCoef,freeCoef, nMat,covMat,curvMat, chiSq, iterStat, myFunc)
192 use sufr_kinds, only: double
193 use sufr_numerics, only: deq0
194
195 implicit none
196 integer, intent(in) :: ny,ndat, ncoef,freecoef(ncoef), nmat
197 real(double), intent(in) :: xdat(ndat), ydat(ny,ndat), yerr(ndat)
198 real(double), intent(inout) :: fcoef(ncoef), iterstat
199 real(double), intent(out) :: curvmat(nmat,nmat), covmat(nmat,nmat), chisq
200
201 integer, parameter :: mmax = 20
202 integer :: ifit,mfit, icoef,cntcoef
203 real(double) :: ochisq,trycoef(mmax),dchisq(mmax),dfcoef(mmax)
204
205 save ochisq,trycoef,dchisq,dfcoef,mfit
206 external myfunc
207
208
209 ! An EXTERNAL subroutine must be CALLed - use a dummy call here, since the subroutine name is only passed on:
210 if(.false.) call myfunc() ! myFunc(nY, xDat(iDat), nCoef,fCoef, yMod,dyda)
211
212
213 ! Initialisation on the first call:
214 if(iterstat.lt.0.d0) then
215 mfit = 0
216 do icoef=1,ncoef
217 if(freecoef(icoef).ne.0) mfit = mfit + 1
218 end do
219
220 iterstat = 0.001d0
221
222 ! Evaluate the linearized curvature matrix and vector dChiSq/dfCoef, and compute chi squared:
223 call nonlin_fit_eval(ny,ndat, xdat,ydat, yerr, ncoef,fcoef,freecoef, nmat,curvmat, dchisq,chisq, myfunc)
224
225 ochisq = chisq
226 trycoef(1:ncoef) = fcoef(1:ncoef)
227 end if
228
229
230 ! Augment the diagonal elements of the variance-covariance matrix:
231 covmat(1:mfit,1:mfit) = curvmat(1:mfit,1:mfit)
232 dfcoef(1:mfit) = dchisq(1:mfit)
233
234 do ifit=1,mfit
235 covmat(ifit,ifit) = curvmat(ifit,ifit) * (1.d0+iterstat)
236 end do
237
238
239 ! Solve the linear algebraic equations using Gauss-Jordan elimination:
240 call solve_linear_equations_gauss_jordan(mfit, nmat,covmat, 1, 1,dfcoef)
241
242
243 ! Compute the variance-covariance and curvature matrices on the last call, and return:
244 if(deq0(iterstat)) then
245 call sort_var_covar_matrix(nmat, covmat, ncoef, freecoef, mfit)
246 call sort_var_covar_matrix(nmat, curvmat, ncoef, freecoef, mfit)
247 return
248 end if
249
250
251 ! Update the trial coefficients:
252 cntcoef = 0
253 do icoef=1,ncoef
254 if(freecoef(icoef).ne.0) then
255 cntcoef = cntcoef+1
256 trycoef(icoef) = fcoef(icoef) + dfcoef(cntcoef)
257 end if
258 end do
259
260
261 ! Evaluate the linearized curvature matrix and vector dChiSq/dfCoef, and compute chi squared:
262 call nonlin_fit_eval(ny,ndat, xdat,ydat, yerr, ncoef,trycoef,freecoef, nmat,covmat, dfcoef, chisq, myfunc)
263
264
265 ! If the new chi squared is better (smaller) than the old value, accept this solution and decrease iterStat...
266 if(chisq.lt.ochisq) then
267 iterstat = 0.1d0*iterstat
268 ochisq = chisq
269
270 curvmat(1:mfit,1:mfit) = covmat(1:mfit,1:mfit)
271 dchisq(1:mfit) = dfcoef(1:mfit)
272
273 fcoef(1:ncoef) = trycoef(1:ncoef)
274
275 else ! ...otherwise keep the old chi squared, and, if larger, increase iterStat:
276
277 if(chisq.gt.ochisq) iterstat = 10*iterstat
278 chisq = ochisq
279
280 end if
281
282 end subroutine nonlin_fit_yerr
283 !*********************************************************************************************************************************
284
285
286 !*********************************************************************************************************************************
287 !> \brief Evaluate the linearized fitting matrix curvMat and vector dChiSq, and calculate the chi squared (chiSq)
288 !!
289 !! \param nY Number of Y values for each X value (normally 1, but e.g. 2 for a sky position with two coordinates)
290 !! \param nDat Number of data points in X and Y
291 !!
292 !! \param xDat X data points to fit
293 !! \param yDat Y data points to fit
294 !! \param yErr Errors (standard deviations) for yDat
295 !!
296 !! \param nCoef Number of coefficients used to describe the non-linear function myFunc
297 !! \param fCoef Coefficients for the non-linear function myFunc, updated after each call
298 !! \param freeCoef Determines which coefficients for the non-linear function myFunc should be fitted for. Set freeCoef(i) = 0 in
299 !! order to keep fCoef(i) fixed
300 !!
301 !! \param nMat Size of the matrices; > nCoef
302 !! \param curvMat Hessian/curvature matrix - double partial derivative of chi squared to two coefficients fCoef
303 !! \param dChiSq Vector containing the partial derivatives of chiSq to each coefficient in fCoef
304 !!
305 !! \param chiSq Chi squared
306 !! \param myFunc External subroutine that describes the model value of Y and partial derivatives dY/dXi for given value X and
307 !! function coefficients fCoef
308 !!
309 !! Since the 1D chi squared is the sum of the squares of the weighted differences,
310 !! \f$\chi^2 = \sum_j d_j^2\f$, and the nY-D distance \f$d_j\f$ is defined as \f$d_j = \sqrt{\sum_i d_{ij}^2}\f$,
311 !! where \f$d_i\f$ is the distance in each dimension, the nY-D chi squared is the sum of
312 !! the squares of these distances, i.e.
313 !! \f$\chi^2 = \sum_j d_j^2 = \sum_j \sum_i d_{ij}^2 = \sum_i \sum_j d_{ij}^2 = \sum_i \chi^2_i\f$,
314 !! simply the sum of the 1D chi squared values. The same holds for the derivatives of
315 !! \f$\chi^2\f$, where the multidimensional derivative is the sum of the 1D values.
316 !!
317 !! \see Numerical Recipes in Fortran, 15.5: Modelling of Data / Non-linear models
318
319 subroutine nonlin_fit_eval(nY,nDat, xDat,yDat, yErr, nCoef,fCoef,freeCoef, nMat,curvMat, dChiSq,chiSq, myFunc)
320 use sufr_kinds, only: double
321 implicit none
322 integer, intent(in) :: ny,ndat, ncoef,freecoef(ncoef), nmat
323 real(double), intent(in) :: xdat(ndat),ydat(ny,ndat),yerr(ndat), fcoef(ncoef)
324 real(double), intent(out) :: chisq,curvmat(nmat,nmat),dchisq(ncoef)
325
326 integer, parameter :: mmax = 20
327 integer :: ifit,jfit,mfit, iy,idat, icoef,jcoef, cntcoefi,cntcoefj
328 real(double) :: err2i,dyda_e2i, dy,ymod(ny),dyda(ny,mmax)
329 external myfunc
330
331
332 ! Determine the number of non-fixed parameters:
333 mfit = 0
334 do icoef=1,ncoef
335 if(freecoef(icoef).ne.0) mfit = mfit + 1
336 end do
337
338
339 ! Initialise the chi squared, the chiSq-derivative vector and the curvature matrix:
340 chisq = 0.d0
341 dchisq = 0.d0
342 curvmat = 0.d0
343
344
345 ! Sum over all data points:
346 do idat=1,ndat
347 call myfunc(ny, xdat(idat), ncoef,fcoef, ymod,dyda)
348
349 err2i = 1.d0/(yerr(idat)**2) ! 1/sigma^2
350
351 do iy=1,ny ! Loop over multiple Y variables (if nY>1)
352 dy = ydat(iy,idat) - ymod(iy)
353
354 cntcoefi = 0
355 do icoef=1,ncoef
356 if(freecoef(icoef).ne.0) then
357 cntcoefi = cntcoefi + 1
358 dyda_e2i = dyda(iy,icoef)*err2i ! dy/dfCoef_i / sigma^2
359
360 cntcoefj = 0
361 do jcoef=1,icoef
362 if(freecoef(jcoef).ne.0) then
363 cntcoefj = cntcoefj + 1
364 curvmat(cntcoefi,cntcoefj) = curvmat(cntcoefi,cntcoefj) + &
365 dyda_e2i*dyda(iy,jcoef) ! Sum dy/dfCoef_i dy/dfCoef_j / sig^2
366 end if
367 end do ! jCoef
368
369 dchisq(cntcoefi) = dchisq(cntcoefi) + dy*dyda_e2i
370 end if
371 end do ! iCoef
372
373 chisq = chisq + dy**2 * err2i ! Compute chi squared
374
375 end do ! iY
376
377 end do ! iDat
378
379
380 ! Fill in the symmetric side of the curvature matrix:
381 do ifit=2,mfit
382 do jfit=1,ifit-1
383 curvmat(jfit,ifit) = curvmat(ifit,jfit)
384 end do ! jFit
385 end do ! iFit
386
387 end subroutine nonlin_fit_eval
388 !*********************************************************************************************************************************
389
390
391 !*********************************************************************************************************************************
392 !> \brief Dummy example function myFunc for nonlin_fit_yerr(): return the value and partial derivatives
393 !!
394 !! \param nY Number of Y values for each X value (normally 1, but e.g. 2 for a sky position with two coordinates)
395 !! \param xDat Input X value for the current data point
396 !!
397 !! \param nCoef Number of coefficients
398 !! \param fCoef Vector of coefficients that describe the function
399 !!
400 !! \param yDat Y values for the current data point (output)
401 !! \param dyda Partial derivatives for yDat: 1: dy/dfCoef(1), ..., n: dy/dfCoef(n) (output)
402 !!
403 !!
404 !! \note Write a subroutine with the same interface to use with nonlin_fit_yerr()
405
406 subroutine nonlin_fit_example_myfunc(nY, xDat, nCoef,fCoef, yDat,dyda)
407 use sufr_kinds, only: double
409
410 implicit none
411 integer, intent(in) :: ny, ncoef
412 real(double), intent(in) :: xdat, fcoef(ncoef)
413 real(double), intent(out) :: ydat(ny), dyda(ny,ncoef)
414
415 if(ny.ne.1) call quit_program_error('nonlin_fit_eval_example_myFunc(): nY must be equal to 1 ', 1)
416 if(ncoef.ne.3) call quit_program_error('nonlin_fit_eval_example_myFunc(): nCoef must be equal to 3 ', 1)
417
418 ydat(1) = fcoef(1)*xdat**2 + fcoef(2) ! Replace with desired function
419 dyda(1,1) = fcoef(2) * xdat ! Replace with partial derivative w.r.t. first variable - dyDat/dfCoef(1)
420 ! ...
421 dyda(1,ncoef) = fcoef(1) ! Replace with partial derivative w.r.t. n-th variable - dyDat/dfCoef(nCoef)
422
423 end subroutine nonlin_fit_example_myfunc
424 !*********************************************************************************************************************************
425
426
427 !*********************************************************************************************************************************
428 !> \brief Sort covariance matrix returned by linear_fit_yerr() and nonlin_fit_yerr() to true order of fitting coefficients
429 !!
430 !! \param nCov Size of both dimensions of covMat()
431 !! \param covMat Variance-covariance matrix
432 !!
433 !! \param nCoef Number of coefficients of the fitting function
434 !! \param freeCoef Fix coefficient coef(i) if freeCoef(i)=0, otherwise fit for it
435 !!
436 !! \param nFit Number of parameters that need to be fit for
437 !!
438 !! \see Numerical Recipes in Fortran 77, Sect.15.4
439 !!
440
441 pure subroutine sort_var_covar_matrix(nCov,covMat, nCoef,freeCoef, nFit)
442 use sufr_kinds, only: double
443 use sufr_system, only: swapdbl
444
445 implicit none
446 integer, intent(in) :: ncov,ncoef, freecoef(ncoef),nfit
447 real(double), intent(inout) :: covmat(ncov,ncov)
448
449 integer :: ii,ij,ik
450
451 do ii=nfit+1,ncoef
452 do ij=1,ii
453 covmat(ii,ij) = 0.d0
454 covmat(ij,ii) = 0.d0
455 end do
456 end do
457
458 ik = nfit
459
460 do ij=ncoef,1,-1
461 if(freecoef(ij).ne.0) then
462 do ii=1,ncoef
463 call swapdbl(covmat(ii,ij), covmat(ii,ik)) ! Swap the two numbers
464 end do
465
466 do ii=1,ncoef
467 call swapdbl(covmat(ij,ii), covmat(ik,ii)) ! Swap the two numbers
468 end do
469
470 ik = ik-1
471 end if
472 end do
473
474 end subroutine sort_var_covar_matrix
475 !*********************************************************************************************************************************
476
477
478
479 !*********************************************************************************************************************************
480 !> \brief Solve a set of linear algebraic equations using Gauss-Jordan elimination.
481 !!
482 !! \param nMat Dimension of the equation set
483 !! \param nMatArr Physical dimensions of the array matArr (nMatArr x nMatArr)
484 !! \param matArr Input: array containing the matrix to be inverted - output: array containing the inverted matrix (I/O)
485 !!
486 !! \param nVec Number of vectors in vecArr
487 !! \param nVecArr One of the physical dimensions of the array vecArr (nMatArr x nVecArr)
488 !! \param vecArr Input: array containing nVec right-hand side vectors - output: solution vectors (I/O)
489 !!
490 !! \see Numerical Recipes in Fortran 77, Sect.2.1
491 !!
492
493 subroutine solve_linear_equations_gauss_jordan(nMat, nMatArr,matArr, nVec, nVecArr,vecArr)
494 use sufr_kinds, only: double
495 use sufr_system, only: warn, swapdbl
496
497 implicit none
498 integer, intent(in) :: nmat,nmatarr, nvec,nvecarr
499 real(double), intent(inout) :: matarr(nmatarr,nmatarr),vecarr(nmatarr,nvecarr)
500
501 integer, parameter :: nmax = 50 ! Maximum allowed value for nMat
502 integer :: ii,icol,irow,ij,ik,il,ll,indxc(nmax),indxr(nmax),ipiv(nmax)
503 real(double) :: arrmax,tmpdbl,pivinv
504
505
506 icol = 0
507 irow = 0
508 ipiv(1:nmat) = 0
509
510
511 do ii=1,nmat
512 ! Find maximum array value:
513 arrmax = 0.d0
514 do ij=1,nmat
515 if(ipiv(ij).ne.1) then
516 do ik=1,nmat
517 if(ipiv(ik).eq.0) then
518 if(abs(matarr(ij,ik)).ge.arrmax) then
519 arrmax = abs(matarr(ij,ik))
520 irow = ij
521 icol = ik
522 end if
523 else if(ipiv(ik).gt.1) then
524 call warn('libSUFR solve_linear_equations_Gauss_Jordan(): singular matrix',0)
525 end if
526 end do
527 end if
528 end do
529
530 ipiv(icol) = ipiv(icol) + 1
531
532 if(irow.ne.icol) then
533 do il=1,nmat
534 call swapdbl(matarr(irow,il), matarr(icol,il))
535 end do
536
537 do il=1,nvec
538 call swapdbl(vecarr(irow,il), vecarr(icol,il))
539 end do
540 end if
541
542 indxr(ii) = irow
543 indxc(ii) = icol
544
545 if(abs(matarr(icol,icol)).lt.10*tiny(matarr)) call warn('libSUFR solve_linear_equations_Gauss_Jordan(): singular matrix', 0)
546
547 pivinv = 1.d0/matarr(icol,icol)
548 matarr(icol,icol) = 1.d0
549
550 matarr(icol,1:nmat) = matarr(icol,1:nmat)*pivinv
551 vecarr(icol,1:nvec) = vecarr(icol,1:nvec)*pivinv
552
553 do ll=1,nmat
554 if(ll.ne.icol) then
555 tmpdbl = matarr(ll,icol)
556 matarr(ll,icol) = 0.d0
557 matarr(ll,1:nmat) = matarr(ll,1:nmat) - matarr(icol,1:nmat)*tmpdbl
558 vecarr(ll,1:nvec) = vecarr(ll,1:nvec) - vecarr(icol,1:nvec)*tmpdbl
559 end if
560 end do
561 end do
562
563 do il=nmat,1,-1
564 if(indxr(il).ne.indxc(il)) then
565 do ik=1,nmat
566 call swapdbl(matarr(ik,indxr(il)), matarr(ik,indxc(il)))
567 end do
568 end if
569 end do
570
571 end subroutine solve_linear_equations_gauss_jordan
572 !*********************************************************************************************************************************
573
574
575
576
577 !*********************************************************************************************************************************
578 !> \brief User-provided base function to fit a polynomial to
579 !!
580 !! \param xVal X value to evaluate yVal = basefunc_polynimial(xVal) for
581 !! \param nCoef Number of coefficients for the base function
582 !!
583 !! \param baseFunc Base function i for coefficent i. For a polynomial, BF(i) = x**(i-1) (output)
584
585 pure subroutine basefunc_polynomial(xVal,nCoef, baseFunc)
586 use sufr_kinds, only: double
587 implicit none
588 integer, intent(in) :: ncoef
589 real(double), intent(in) :: xval
590 real(double), intent(out) :: basefunc(ncoef)
591
592 integer :: coefi
593
594 basefunc(1) = 1.d0
595 do coefi = 2,ncoef
596 basefunc(coefi) = basefunc(coefi-1) * xval
597 end do
598
599 end subroutine basefunc_polynomial
600 !*********************************************************************************************************************************
601
602
603
604
605end module sufr_fitting
606!***********************************************************************************************************************************
607
Procedures to fit functions to data.
Definition fitting.f90:23
subroutine, public linear_fit_yerr(ndat, xdat, ydat, yerr, ncoef, fcoef, freecoef, ncov, covmat, chisq, myfunc)
Fit the model coefficients using a chi^2 method.
Definition fitting.f90:70
subroutine, public nonlin_fit_example_myfunc(ny, xdat, ncoef, fcoef, ydat, dyda)
Dummy example function myFunc for nonlin_fit_yerr(): return the value and partial derivatives.
Definition fitting.f90:407
subroutine, public nonlin_fit_yerr(ny, ndat, xdat, ydat, yerr, ncoef, fcoef, freecoef, nmat, covmat, curvmat, chisq, iterstat, myfunc)
Levenberg-Marquardt method to reduce the value of chi-squared of a fit of a set of data points with e...
Definition fitting.f90:192
pure subroutine, public basefunc_polynomial(xval, ncoef, basefunc)
User-provided base function to fit a polynomial to.
Definition fitting.f90:586
Provides kinds and related constants/routines.
Definition kinds.f90:26
integer, parameter double
Double-precision float. Precision = 15, range = 307.
Definition kinds.f90:35
Procedures for numerical operations.
Definition numerics.f90:23
elemental logical function deq0(x0, eps)
Test whether a double-precision variable is equal to zero better than a given value (default: 2x mach...
Definition numerics.f90:118
System-related procedures.
Definition system.f90:23
subroutine quit_program_error(message, status)
Print an error message to StdErr and stop the execution of the current program.
Definition system.f90:78
subroutine warn(message, unit)
Print a warning to StdOut or StErr.
Definition system.f90:646
pure subroutine swapdbl(dbl1, dbl2)
Swap two double-precision real variables.
Definition system.f90:1034