aboutsummaryrefslogtreecommitdiff
path: root/noao/imred/vtel/mrqmin.x
diff options
context:
space:
mode:
Diffstat (limited to 'noao/imred/vtel/mrqmin.x')
-rw-r--r--noao/imred/vtel/mrqmin.x348
1 files changed, 348 insertions, 0 deletions
diff --git a/noao/imred/vtel/mrqmin.x b/noao/imred/vtel/mrqmin.x
new file mode 100644
index 00000000..197e7931
--- /dev/null
+++ b/noao/imred/vtel/mrqmin.x
@@ -0,0 +1,348 @@
+# MRQMIN -- Levenberg-Marquard nonlinear chi square minimization.
+# From NUMERICAL RECIPES by Press, Flannery, Teukolsky, and Vetterling, p526.
+#
+# Levenberg-Marquardt method, attempting to reduce the value of chi
+# square of a fit between a set of NDATA points X,Y with individual
+# standard deviations SIG, and a nonlinear function dependent on MA
+# coefficients A. The array LISTA numbers the parameters A such that the
+# first MFIT elements correspond to values actually being adjusted; the
+# remaining MA-MFIT parameters are held fixed at their input value. The
+# program returns the current best-fit values for the MA fit parameters
+# A, and chi square, CHISQ. The arrays COVAR and ALPHA with physical
+# dimension NCA (>= MFIT) are used as working space during most
+# iterations. Supply a subroutine FUNCS(X,A,YFIT,DYDA,MA) that evaluates
+# the fitting function YFIT, and its derivatives DYDA with respect to the
+# fitting parameters A at X. On the first call provide an initial guess
+# for the parameters A, and set ALAMDA<0 for initialization (which then
+# sets ALAMDA=0.001). If a step succeeds CHISQ becomes smaller and
+# ALAMDA decreases by a factor of 10. If a step fails ALAMDA grows by a
+# factor of 10. You must call this routine repeatedly until convergence
+# is achieved. Then make one final call with ALAMDA = 0, so that COVAR
+# returns the covariance matrix, and ALPHA the curvature matrix.
+#
+# This routine is cast in the IRAF SPP language but the variable names have
+# been maintained for reference to the original source. Also the working
+# arrays ATRY, BETA, and DA are allocated dynamically to eliminate
+# limitations on the number of parameters fit.
+
+procedure mrqmin (x, y, sig, ndata, a, ma, lista, mfit, covar, alpha, nca,
+ chisq, funcs, alamda)
+
+real x[ndata] # X data array
+real y[ndata] # Y data array
+real sig[ndata] # Sigma array
+int ndata # Number of data points
+real a[ma] # Parameter array
+int ma # Number of parameters
+int lista[ma] # List array indexing parameters to fit
+int mfit # Number of parameters to fit
+real covar[nca,nca] # Covariance matrix
+real alpha[nca,nca] # Curvature matrix
+int nca # Matrix dimension (>= mfit)
+real chisq # Chi square of fit
+extern funcs # Function to compute derivatives
+real alamda # Initialization and convergence parameter
+
+int j, k, kk, ihit
+real ochisq
+pointer atry, beta, da
+
+errchk gaussj
+
+begin
+ # Initialize and check that LISTA contains a proper permutation.
+ if (alamda < 0.) {
+ call mfree (atry, TY_REAL)
+ call mfree (beta, TY_REAL)
+ call mfree (da, TY_REAL)
+ call malloc (atry, ma, TY_REAL)
+ call malloc (beta, mfit, TY_REAL)
+ call malloc (da, mfit, TY_REAL)
+
+ kk = mfit + 1
+ do j = 1, ma {
+ ihit = 0
+ do k = 1, mfit
+ if (lista(k) == j)
+ ihit = ihit + 1
+ if (ihit == 0) {
+ lista (kk) = j
+ kk = kk + 1
+ } else if (ihit > 1)
+ call error (0, "Improper permutation in LISTA")
+ }
+ if (kk != (ma + 1))
+ call error (0, "Improper permutation in LISTA")
+ alamda = 0.001
+ call mrqcof (x, y, sig, ndata, a, ma, lista, mfit, alpha,
+ Memr[beta], nca, chisq, funcs)
+ ochisq = chisq
+ do j = 1, ma
+ Memr[atry+j-1] = a[j]
+ }
+
+ # Alter linearized fitting matrix by augmenting diagonal elements.
+ do j = 1, mfit {
+ do k = 1, mfit
+ covar[j,k] = alpha[j,k]
+ covar[j,j] = alpha[j,j] * (1. + alamda)
+ Memr[da+j-1] = Memr[beta+j-1]
+ }
+
+ # Matrix solution.
+ call gaussj (covar, mfit, nca, Memr[da], 1, 1)
+
+ # Once converged evaluate covariance matrix with ALAMDA = 0.
+ if (alamda == 0.) {
+ call covsrt (covar, nca, ma, lista, mfit)
+ call mfree (atry, TY_REAL)
+ call mfree (beta, TY_REAL)
+ call mfree (da, TY_REAL)
+ return
+ }
+
+ # Did the trial succeed?
+ do j = 1, mfit
+ Memr[atry+lista[j]-1] = a[lista[j]] + Memr[da+j-1]
+ call mrqcof (x, y, sig, ndata, Memr[atry], ma, lista, mfit, covar,
+ Memr[da], nca, chisq, funcs)
+
+ # Success - accept the new solution, Failure - increase ALAMDA
+ if (chisq < ochisq) {
+ alamda = 0.1 * alamda
+ ochisq = chisq
+ do j = 1, mfit {
+ do k = 1, mfit
+ alpha[j,k] = covar[j,k]
+ Memr[beta+j-1] = Memr[da+j-1]
+ a[lista[j]] = Memr[atry+lista[j]-1]
+ }
+ } else {
+ alamda = 10. * alamda
+ chisq = ochisq
+ }
+end
+
+
+# MRQCOF -- Evaluate linearized matrix coefficients.
+# From NUMERICAL RECIPES by Press, Flannery, Teukolsky, and Vetterling, p527.
+#
+# Used by MRQMIN to evaluate the linearized fitting matrix ALPHA and vector
+# BETA.
+#
+# This procedure has been recast in the IRAF/SPP language but the variable
+# names have been maintained. Dynamic memory is used.
+
+procedure mrqcof (x, y, sig, ndata, a, ma, lista, mfit, alpha, beta, nalp,
+ chisq, funcs)
+
+real x[ndata] # X data array
+real y[ndata] # Y data array
+real sig[ndata] # Sigma array
+int ndata # Number of data points
+real a[ma] # Parameter array
+int ma # Number of parameters
+int lista[ma] # List array indexing parameters to fit
+int mfit # Number of parameters to fit
+real alpha[nalp,nalp] # Work matrix
+real beta[ma] # Work array
+int nalp # Matrix dimension (>= mfit)
+real chisq # Chi square of fit
+extern funcs # Function to compute derivatives
+
+int i, j, k
+real sig2i, ymod, dy, wt
+pointer sp, dyda
+
+begin
+ call smark (sp)
+ call salloc (dyda, ma, TY_REAL)
+
+ do j = 1, mfit {
+ do k = 1, j
+ alpha[j,k] = 0.
+ beta[j] = 0.
+ }
+
+ chisq = 0.
+ do i = 1, ndata {
+ call funcs (x[i], a, ymod, Memr[dyda], ma)
+ sig2i = 1. / (sig[i] * sig[i])
+ dy = y[i] - ymod
+ do j = 1, mfit {
+ wt = Memr[dyda+lista[j]-1] * sig2i
+ do k = 1, j
+ alpha[j,k] = alpha[j,k] + wt * Memr[dyda+lista[k]-1]
+ beta[j] = beta[j] + dy * wt
+ }
+ chisq = chisq + dy * dy * sig2i
+ }
+
+ do j = 2, mfit
+ do k = 1, j-1
+ alpha[k,j] = alpha[j,k]
+
+ call sfree (sp)
+end
+
+
+# GAUSSJ -- Linear equation solution by Gauss-Jordan elimination.
+# From NUMERICAL RECIPES by Press, Flannery, Teukolsky, and Vetterling, p28.
+#
+# Linear equation solution by Gauss-Jordan elimination. A is an input matrix
+# of N by N elements, stored in an array of physical dimensions NP by
+# NP. B is an input matrix of N by M containing the M right-hand side
+# vectors, stored in an array of physical dimensions NP by MP. On
+# output, A is replaced by its matrix inverse, and B is replaced by the
+# corresponding set of solutionn vectors.
+#
+# This procedure has been recast in the IRAF/SPP language using dynamic
+# memory allocation and error return. The variable names have been maintained.
+
+procedure gaussj (a, n, np, b, m, mp)
+
+real a[np,np] # Input matrix and returned inverse
+int n # Dimension of input matrix
+int np # Storage dimension of input matrix
+real b[np,mp] # Input RHS matrix and returned solution
+int m # Dimension of input matrix
+int mp # Storage dimension of input matrix
+
+int i, j, k, l, ll, irow, icol, indxrl, indxcl
+real big, pivinv, dum
+pointer sp, ipiv, indxr, indxc
+
+begin
+ call smark (sp)
+ call salloc (ipiv, n, TY_INT)
+ call salloc (indxr, n, TY_INT)
+ call salloc (indxc, n, TY_INT)
+
+ do j = 1, n
+ Memi[ipiv+j-1] = 0
+
+ do i = 1, n {
+ big = 0.
+ do j = 1, n {
+ if (Memi[ipiv+j-1] != 1) {
+ do k = 1, n {
+ if (Memi[ipiv+k-1] == 0) {
+ if (abs (a[j,k]) >= big) {
+ big = abs (a[j,k])
+ irow = j
+ icol = k
+ }
+ } else if (Memi[ipiv+k-1] > 1) {
+ call sfree (sp)
+ call error (0, "Singular matrix")
+ }
+ }
+ }
+ }
+
+ Memi[ipiv+icol-1] = Memi[ipiv+icol-1] + 1
+
+ if (irow != icol) {
+ do l = 1, n {
+ dum = a[irow,l]
+ a[irow,l] = a[icol,l]
+ a[icol,l] = dum
+ }
+ do l = 1, m {
+ dum = b[irow,l]
+ b[irow,l] = b[icol,l]
+ b[icol,l] = dum
+ }
+ }
+ Memi[indxr+i-1] = irow
+ Memi[indxc+i-1] = icol
+ if (a[icol,icol] == 0.) {
+ call sfree (sp)
+ call error (0, "Singular matrix")
+ }
+ pivinv = 1. / a[icol,icol]
+ a[icol,icol] = 1
+ do l = 1, n
+ a[icol,l] = a[icol,l] * pivinv
+ do l = 1, m
+ b[icol,l] = b[icol,l] * pivinv
+ do ll = 1, n {
+ if (ll != icol) {
+ dum = a[ll,icol]
+ do l = 1, n
+ a[ll,l] = a[ll,l] - a[icol,l] * dum
+ do l = 1, m
+ b[ll,l] = b[ll,l] - b[icol,l] * dum
+ }
+ }
+ }
+
+ do l = n, 1, -1 {
+ indxrl = Memi[indxr+l-1]
+ indxcl = Memi[indxr+l-1]
+ if (indxrl != indxcl) {
+ do k = 1, n {
+ dum = a[k,indxrl]
+ a[k,indxrl] = a[k,indxcl]
+ a[k,indxcl] = dum
+ }
+ }
+ }
+
+ call sfree (sp)
+end
+
+
+# COVSRT -- Sort covariance matrix.
+# From NUMERICAL RECIPES by Press, Flannery, Teukolsky, and Vetterling, p515.
+#
+# Given the covariance matrix COVAR of a fit for MFIT of MA total parameters,
+# and their ordering LISTA, repack the covariance matrix to the true order of
+# the parameters. Elements associated with fixed parameters will be zero.
+# NCVM is the physical dimension of COVAR.
+#
+# This procedure has been recast into the IRAF/SPP language but the
+# original variable names are used.
+
+procedure covsrt (covar, ncvm, ma, lista, mfit)
+
+real covar[ncvm,ncvm] # Input and output array
+int ncvm # Physical dimension of array
+int ma # Number of parameters
+int lista[mfit] # Index of fitted parameters
+int mfit # Number of fitted parameters
+
+int i, j
+real swap
+
+begin
+ # Zero all elements below diagonal.
+ do j = 1, ma-1
+ do i = j+1, ma
+ covar[i,j] = 0.
+
+ # Repack off-diag elements of fit into correct locations below diag.
+ do i = 1, mfit-1
+ do j = i+1, mfit
+ if (lista[j] > lista[i])
+ covar [lista[j],lista[i]] = covar[i,j]
+ else
+ covar [lista[i],lista[j]] = covar[i,j]
+
+ # Temporarily store original diag elements in top row and zero diag.
+ swap = covar[1,1]
+ do j = 1, ma {
+ covar[1,j] = covar[j,j]
+ covar[j,j] = 0.
+ }
+ covar[lista[1],lista[1]] = swap
+
+ # Now sort elements into proper order on diagonal.
+ do j = 2, mfit
+ covar[lista[j],lista[j]] = covar[1,j]
+
+ # Finally, fill in above diagonal by symmetry.
+ do j = 2, ma
+ do i = 1, j-1
+ covar[i,j] = covar[j,i]
+end