aboutsummaryrefslogtreecommitdiff
path: root/noao/digiphot/photcal/evaluate/phinvert.x
diff options
context:
space:
mode:
authorJoseph Hunkeler <jhunkeler@gmail.com>2015-07-08 20:46:52 -0400
committerJoseph Hunkeler <jhunkeler@gmail.com>2015-07-08 20:46:52 -0400
commitfa080de7afc95aa1c19a6e6fc0e0708ced2eadc4 (patch)
treebdda434976bc09c864f2e4fa6f16ba1952b1e555 /noao/digiphot/photcal/evaluate/phinvert.x
downloadiraf-linux-fa080de7afc95aa1c19a6e6fc0e0708ced2eadc4.tar.gz
Initial commit
Diffstat (limited to 'noao/digiphot/photcal/evaluate/phinvert.x')
-rw-r--r--noao/digiphot/photcal/evaluate/phinvert.x619
1 files changed, 619 insertions, 0 deletions
diff --git a/noao/digiphot/photcal/evaluate/phinvert.x b/noao/digiphot/photcal/evaluate/phinvert.x
new file mode 100644
index 00000000..9d7ee14b
--- /dev/null
+++ b/noao/digiphot/photcal/evaluate/phinvert.x
@@ -0,0 +1,619 @@
+include <mach.h>
+include "../lib/parser.h"
+
+# PH_IVINIT -- Preallocate the space required by the inversion code.
+
+procedure ph_ivinit (nstd, nustd, neq)
+
+int nstd # number of catalog variables
+int nustd # number of catalog variables to be fit
+int neq # number of equations
+
+include "invert.com"
+
+begin
+ call malloc (py, neq, TY_REAL)
+ call malloc (pyfit, neq, TY_REAL)
+ call malloc (pa, nstd, TY_REAL)
+ call malloc (pdelta, nstd, TY_REAL)
+ call malloc (pda, nstd, TY_REAL)
+
+ call malloc (palpha, nustd * nustd, TY_DOUBLE)
+ call malloc (pbeta, nustd, TY_REAL)
+ call malloc (pik, nustd, TY_INT)
+ call malloc (pjk, nustd, TY_INT)
+
+ call malloc (pyerr, neq, TY_REAL)
+ call malloc (pafit, nstd, TY_REAL)
+end
+
+
+# PH_IVFREE -- Free the space required by the inversion code.
+
+procedure ph_ivfree ()
+
+include "invert.com"
+
+begin
+ call mfree (py, TY_REAL)
+ call mfree (pyfit, TY_REAL)
+ call mfree (pa, TY_REAL)
+ call mfree (pdelta, TY_REAL)
+ call mfree (pda, TY_REAL)
+
+ call mfree (palpha, TY_DOUBLE)
+ call mfree (pbeta, TY_REAL)
+ call mfree (pik, TY_INT)
+ call mfree (pjk, TY_INT)
+
+ call mfree (pyerr, TY_REAL)
+ call mfree (pafit, TY_REAL)
+end
+
+
+# PH_OBJCHECK -- Check that the equations for this particular star are
+# invertable.
+
+int procedure ph_objcheck (params, a, vartable, nstdvars, nreq, eqset,
+ maxnset, vindex, nvar, eqindex, neq)
+
+pointer params[ARB] # array of pointers to the fitted parameters
+real a[ARB] # array of observed and catalog variables
+int vartable[nstdvars,ARB] # table of variables as a function of equation
+int nstdvars # the total number of catalog variables
+int nreq # the total number of reference equations
+int eqset[maxnset,ARB] # set equation table
+int maxnset # maximum number of set equations
+int vindex[ARB] # output index of variables
+int nvar # number of variables used in the equations
+int eqindex[ARB] # output index of equations
+int neq # number of equations to be reduced
+
+int i, j, sym, ncat, nset
+real rval
+int pr_gsym()
+pointer pr_gsymp()
+real pr_eval()
+
+begin
+ # Initialize
+ call aclri (vindex, nstdvars)
+ call aclri (eqindex, nreq)
+
+ # Evalute the reference equations.
+ neq = 0
+ do i = 1, nreq {
+ sym = pr_gsym (i, PTY_TRNEQ)
+ rval = pr_eval (pr_gsymp (sym, PTEQRPNREF), a, Memr[params[i]])
+ if (IS_INDEFR(rval))
+ next
+ neq = neq + 1
+ eqindex[neq] = i
+ }
+
+ # If there is no data return.
+ if (neq <= 0)
+ return (ERR)
+
+ # Determine which variables are used by the reduced set of equations.
+ do i = 1, neq {
+ do j = 1, nstdvars {
+ if (vartable[j,eqindex[i]] == 0)
+ next
+ vindex[j] = vartable[j,eqindex[i]]
+ }
+ }
+
+ # Deterine which set equations are used by the reduced set of equations
+ nset = 0
+ do j = 1, maxnset {
+ do i = 1, neq {
+ if (eqset[j,eqindex[i]] == 0)
+ next
+ nset = nset + 1
+ break
+ }
+ }
+
+ # Count the number of variables.
+ nvar = 0
+ ncat = 0
+ do j = 1, nstdvars {
+ if (vindex[j] == 0)
+ next
+ nvar = nvar + 1
+ if (vindex[j] > 0)
+ ncat = ncat + 1
+ }
+
+ if ((ncat + nset) > neq)
+ return (ERR)
+
+ return (OK)
+end
+
+
+define MAX_NITER1 10 # maximum number of iterations
+define MAX_NITER2 50 # maximum number of trials
+define DET_TOL 1.0E-20 # minimum value of the determinant
+#define DET_TOL 0.0 # minimum value of the determinant
+define MIN_DELTA 0.01 # minimum absolute value of
+ # parameter increments
+
+# PH_INVERT -- Invert the transformation to compute the standard indices.
+
+int procedure ph_invert (params, a, nobs, deltaa, aindex, nstd,
+ nustd, eqindex, nueq)
+
+pointer params[ARB] # input array of pointers to the fitted parameters
+real a[ARB] # array of observed and catalog variables
+int nobs # the number of observed variables
+real deltaa[ARB] # array of increments for the catalog variables
+int aindex[ARB] # index of active catalog variables
+int nstd # total number of catalog variables
+int nustd # number of catalog variables to be fit
+int eqindex[ARB] # the equation index
+int nueq # total number of equations used
+
+int i, sym, niter
+real stdev1, stdev2, det, rms
+int pr_gsym()
+pointer pr_gsymp()
+real pr_eval(), ph_accum(), ph_incrms()
+
+include "invert.com"
+
+begin
+ # Evalute the reference equations.
+ do i = 1, nueq {
+ sym = pr_gsym (eqindex[i], PTY_TRNEQ)
+ Memr[py+i-1] = pr_eval (pr_gsymp (sym, PTEQRPNREF), a,
+ Memr[params[eqindex[i]]])
+ if (IS_INDEFR(Memr[py+i-1]))
+ return (ERR)
+ }
+
+ # Initialize the parameter increments. This will be incremented
+ # each time through the fitting loop.
+ call amovr (deltaa, Memr[pdelta], nstd)
+
+ # Accumulate the matrices and vectors, do the inversion and compute
+ # the new parameter increments. The fit will terminate when the
+ # determinant of the inversion matrix becomes < 1.0e-20, if the
+ # standard deviation of the fit begins to increase, if the rms of
+ # the fit < EPSILONR, or the maximum number of iterations is
+ # exceeded, whichever comes first.
+
+ niter = 0
+
+ repeat {
+
+ # Compute the curvature currection. Return INDEFR if there are
+ # bad data in the fit. Terminate the fit if the determinant of
+ # the curvature matrix is too close to zero.
+
+ stdev1 = ph_accum (params, Memr[py], Memr[pyfit], eqindex, nueq,
+ a, nobs, Memr[pdelta], aindex, Memr[pda], nstd,
+ Memd[palpha], Memr[pbeta], Memi[pik], Memi[pjk], nustd, det)
+
+ #call eprintf ("acc: niter=%d det=%g stdev1=%g\n")
+ #call pargi (niter+1)
+ #call pargr (det)
+ #call pargr (stdev1)
+
+ # Return if there is INDEF data in the fit.
+ if (IS_INDEFR(stdev1))
+ return (ERR)
+
+ # Check the size of the determinant but force at least one fit.
+ if ((abs (det) < DET_TOL) && (niter > 0))
+ break
+
+ # Find the new parameter values.
+ call amovr (a, Memr[pa], nstd)
+ stdev2 = ph_incrms (params, Memr[py], Memr[pyfit], eqindex, nueq,
+ a, nobs, Memr[pda], aindex, nstd, stdev1)
+
+ #call eprintf ("inc: niter=%d det=%g stdev2=%g\n")
+ #call pargi (niter+1)
+ #call pargr (det)
+ #call pargr (stdev2)
+
+ # Check the new values.
+ if (IS_INDEFR(stdev2) || (stdev2 >= stdev1)) {
+ if (niter == 0)
+ return (ERR)
+ else {
+ call amovr (Memr[pa], a, nstd)
+ return (OK)
+ }
+ }
+
+ # User the new deltas and increment the fit counters.
+ call anegr (Memr[pda], Memr[pdelta], nstd)
+ call ph_deltamin (Memr[pdelta], MIN_DELTA, Memr[pdelta], nstd)
+ niter = niter + 1
+ rms = sqrt (stdev2)
+
+ } until ((niter == MAX_NITER1) || (rms <= EPSILONR))
+
+ return (OK)
+end
+
+
+# PH_ACCUM -- Accumulate the matrix of second derivatives and vector
+# of first derivatives required for parabolic expansion of the rms
+# non-linear least squares fitting technique. This code is a modification
+# of the Bevington CHIFIT subroutine where the reduced chi-squared has
+# been replaced by the rms. The original CHIFIT cannot be used to fit the
+# case when there are n data points and n unknowns since the number of
+# degrees of freedom is zero and hence so is the reduced chi-squared.
+
+real procedure ph_accum (params, y, yfit, eqindex, neq, a, nobs, deltaa,
+ aindex, da, nstd, alpha, beta, ik, jk, nustd, det)
+
+pointer params[ARB] # input array of ptrs to the fitted parameters
+real y[ARB] # array of reference equation values
+real yfit[ARB] # array of fitted reference equation values
+int eqindex[ARB] # the equation indices
+int neq # number of equations to be inverted
+real a[ARB] # array of observed and catalog variables
+int nobs # the number of observed variables
+real deltaa[ARB] # array of increments for the catalog variables
+int aindex[ARB] # index of active catalog variables
+real da[ARB] # new array of parameter increments
+int nstd # number of catalog variables
+double alpha[nustd,ARB] # the matrix of second derivatives
+real beta[ARB] # the vector of first derivatives
+int ik[ARB] # working array for the matrix inversion
+int jk[ARB] # working array for the matrix inversion
+int nustd # The number of catalog variables to be fit
+real det # determinant of inverted matrix
+
+int i, j, k, nj, nk, sym
+real aj, ak, rms1, rms2, rms3
+int pr_gsym()
+pointer pr_gsymp()
+real pr_eval()
+
+begin
+ # Compute the initial rms, checking for INDEF valued variables.
+ rms1 = 0.0
+ do i = 1, neq {
+ sym = pr_gsym (eqindex[i], PTY_TRNEQ)
+ yfit[i] = pr_eval (pr_gsymp (sym, PTEQRPNFIT), a,
+ Memr[params[eqindex[i]]])
+ if (IS_INDEFR(yfit[i]))
+ return (INDEFR)
+ rms1 = rms1 + (y[i] - yfit[i]) ** 2
+ }
+ rms1 = rms1 / neq
+
+ nj = 0
+ do j = 1, nstd {
+
+ # Check the status of the parameter.
+ if (aindex[j] == 0)
+ next
+ nj = nj + 1
+
+ # Increment each parameter.
+ aj = a[j+nobs]
+ a[j+nobs] = aj + deltaa[j]
+
+ # Compute a new rms.
+ rms2 = 0.0
+ do i = 1, neq {
+ sym = pr_gsym (eqindex[i], PTY_TRNEQ)
+ yfit[i] = pr_eval (pr_gsymp (sym, PTEQRPNFIT), a,
+ Memr[params[eqindex[i]]])
+ rms2 = rms2 + (y[i] - yfit[i]) ** 2
+ }
+ rms2 = rms2 / neq
+
+ # Begin accumulating the diagonal elements .
+ alpha[nj,nj] = rms2 - 2.0 * rms1
+ beta[nj] = -rms2
+
+ # Accumulate the non-diagonal elements.
+ nk = 0
+ do k = 1, nstd {
+
+ if (aindex[k] == 0)
+ next
+ nk = nk + 1
+
+ if ((nk - nj) == 0)
+ next
+ else if ((nk - nj) < 0) {
+ alpha[nk,nj] = (alpha[nk,nj] - rms2) / 2.0
+ alpha[nj,nk] = alpha[nk,nj]
+ next
+ }
+
+ alpha[nj,nk] = rms1 - rms2
+ ak = a[k+nobs]
+ a[k+nobs] = ak + deltaa[k]
+
+ rms3 = 0.0
+ do i = 1, neq {
+ sym = pr_gsym (eqindex[i], PTY_TRNEQ)
+ yfit[i] = pr_eval (pr_gsymp (sym, PTEQRPNFIT), a,
+ Memr[params[eqindex[i]]])
+ rms3 = rms3 + (y[i] - yfit[i]) ** 2
+ }
+ rms3 = rms3 / neq
+
+ alpha[nj,nk] = alpha[nj,nk] + rms3
+ a[k+nobs] = ak
+ }
+
+ # Continue accumulating the diagonal elements.
+ a[j+nobs] = aj - deltaa[j]
+ rms3 = 0.0
+ do i = 1, neq {
+ sym = pr_gsym (eqindex[i], PTY_TRNEQ)
+ yfit[i] = pr_eval (pr_gsymp (sym, PTEQRPNFIT), a,
+ Memr[params[eqindex[i]]])
+ rms3 = rms3 + (y[i] - yfit[i]) ** 2
+ }
+ rms3 = rms3 / neq
+
+ a[j+nobs] = aj
+ alpha[nj,nj] = (alpha[nj,nj] + rms3) / 2.0
+ beta[nj] = (beta[nj] + rms3) / 4.0
+ }
+
+ # Eliminate any curvature from the matrix of second derivatives.
+ do j = 1, nj {
+ if (alpha[j,j] > 0.0)
+ next
+ if (alpha[j,j] < 0.0)
+ alpha[j,j] = -alpha[j,j]
+ else
+ alpha[j,j] = 0.01
+ do k = 1, nk {
+ if ((k - j) == 0)
+ next
+ alpha[j,k] = 0.0
+ alpha[k,j] = 0.0
+ }
+ }
+
+ # Invert the matrix.
+ call phminv (alpha, ik, jk, nj, det)
+
+ # Increment the parameters.
+ nj = 0
+ do j = 1, nstd {
+ da[j] = 0.0
+ if (aindex[j] == 0)
+ next
+ nj = nj + 1
+ nk = 0
+ do k = 1, nstd {
+ if (aindex[k] == 0)
+ next
+ nk = nk + 1
+ da[j] = da[j] + beta[nk] * alpha[nj,nk]
+ }
+ da[j] = 0.2 * da[j] * deltaa[j]
+ }
+
+ # If the determinate is too small increment the parameters by
+ # deltas and try again.
+ #if (abs (det) < DET_TOL) {
+ #call eprintf ("using approx\n")
+ #do j = 1, nstd {
+ #if (aindex[j] == 0) {
+ #da[j] = 0.0
+ #next
+ #}
+ #call eprintf ("i=%d dain=%g ")
+ #call pargi (j)
+ #call pargr (da[j])
+ #if (da[j] > 0.0)
+ #da[j] = abs (deltaa[j])
+ #else if (da[j] < 0.0)
+ #da[j] = -abs (deltaa[j])
+ #else
+ #da[j] = 0.0
+ #call eprintf ("daout=%g\n")
+ #call pargr (da[j])
+ #}
+ #}
+
+ return (rms1)
+end
+
+
+# PH_INCRMS -- Increment the parameters until three values of the rms are found
+# which bracket the best fitting data point and fit a parabola to the three
+# different rms points.
+
+real procedure ph_incrms (params, y, yfit, eqindex, neq, a, nobs, da, aindex,
+ nstd, rms1)
+
+pointer params[ARB] # input array of ptrs to the fitted parameters
+real y[ARB] # the array of reference equation values
+real yfit[ARB] # the array of fitted reference equation values
+int eqindex[ARB] # list of active equations
+int neq # the number of equations
+real a[ARB] # array of observed and fitted variables
+int nobs # number of observed variables
+real da[ARB] # the parameter increments
+int aindex[ARB] # the index of active catalog variables
+int nstd # number of catalog variables
+real rms1 # the first rms point
+
+int j, i, sym, niter
+real orms2, rms2, orms3, rms3, delta, rms
+int pr_gsym()
+pointer pr_gsymp()
+real pr_eval()
+
+begin
+ # Adjust the parameters.
+ rms = rms1
+ do j = 1, nstd {
+ if (aindex[j] == 0)
+ next
+ a[j+nobs] = a[j+nobs] + da[j]
+ }
+
+ # Alter the parameter increments until the rms starts to decrease.
+ orms2 = MAX_REAL
+ niter = 0
+ repeat {
+
+ rms2 = 0.0
+ do i = 1, neq {
+ sym = pr_gsym (eqindex[i], PTY_TRNEQ)
+ yfit[i] = pr_eval (pr_gsymp (sym, PTEQRPNFIT), a,
+ Memr[params[eqindex[i]]])
+ rms2 = rms2 + (y[i] - yfit[i]) ** 2
+ }
+ rms2 = rms2 / neq
+ #call eprintf (" niter=%d rms1=%g rms2=%g\n")
+ #call pargi (niter)
+ #call pargr (rms1)
+ #call pargr (rms2)
+ if (rms2 <= 0.0)
+ break
+ if ((rms1 - rms2) >= 0.0)
+ break
+
+ # If rms2 does not decrease and does not change from one iteration
+ # to the next we are probably near the precision limits of the
+ # computer or the computed curvature has the wrong sign. In that
+ # case quit.
+
+ if (orms2 < MAX_REAL) {
+ if (abs ((rms2 - orms2) / orms2) < EPSILONR)
+ return (rms)
+ }
+
+ orms2 = rms2
+ niter = niter + 1
+ if (niter >= MAX_NITER2)
+ return (rms)
+
+ do j = 1, nstd {
+ if (aindex[j] == 0)
+ next
+ #da[j] = da[j] / 2.0
+ a[j+nobs] = a[j+nobs] - da[j]
+ }
+
+
+ }
+
+ # Alter the parameter increments until the rms starts to increase.
+ orms3 = MAX_REAL
+ niter = 0
+ repeat {
+
+ do j = 1, nstd {
+ if (aindex[j] == 0)
+ next
+ a[j+nobs] = a[j+nobs] + da[j]
+ }
+
+ rms3 = 0.0
+ do i = 1, neq {
+ sym = pr_gsym (eqindex[i], PTY_TRNEQ)
+ yfit[i] = pr_eval (pr_gsymp (sym, PTEQRPNFIT), a,
+ Memr[params[eqindex[i]]])
+ rms3 = rms3 + (y[i] - yfit[i]) ** 2
+ }
+ rms3 = rms3 / neq
+ #call eprintf (" niter=%d rms1=%g rms2=%g rms3=%g\n")
+ #call pargi (niter)
+ #call pargr (rms1)
+ #call pargr (rms2)
+ #call pargr (rms3)
+ if ((rms3 - rms2) >= 0.0)
+ break
+
+ if (orms3 < MAX_REAL) {
+ if (abs ((rms3 - orms3) / orms3) < EPSILONR)
+ return (rms)
+ }
+
+ niter = niter + 1
+ if (niter >= MAX_NITER2)
+ return (rms)
+
+
+ orms3 = rms3
+ rms1 = rms2
+ rms2 = rms3
+
+ }
+
+ # Fit a parabola to the three values of the rms that bracket the fit.
+ if (rms3 <= rms2)
+ delta = 1.0
+ else
+ delta = 1.0 / (1.0 + (rms1 - rms2) / (rms3 - rms2)) + 0.5
+ do j = 1, nstd {
+ if (aindex[j] == 0)
+ next
+ a[nobs+j] = a[nobs+j] - delta * da[j]
+ }
+
+ rms = 0.0
+ do i = 1, neq {
+ sym = pr_gsym (eqindex[i], PTY_TRNEQ)
+ yfit[i] = pr_eval (pr_gsymp (sym, PTEQRPNFIT), a,
+ Memr[params[eqindex[i]]])
+ rms = rms + (y[i] - yfit[i]) ** 2
+ }
+ rms = rms / neq
+
+ if ((rms2 - rms) < 0.0) {
+ do j = 1, nstd {
+ if (aindex[j] == 0)
+ next
+ a[nobs+j] = a[nobs+j] + (delta - 1.) * da[j]
+ }
+ do i = 1, neq {
+ sym = pr_gsym (eqindex[i], PTY_TRNEQ)
+ yfit[i] = pr_eval (pr_gsymp (sym, PTEQRPNFIT), a,
+ Memr[params[eqindex[i]]])
+ }
+ rms = rms2
+ }
+
+ #call eprintf (" incr: rms1=%g rms2=%g rms3=%g rms=%g\n")
+ #call pargr (rms1)
+ #call pargr (rms2)
+ #call pargr (rms3)
+ #call pargr (rms)
+
+ return (rms)
+end
+
+
+# PH_DELTAMIN -- Check to make sure that the absolute value of the deltaa
+# is always greater than or equal to min_delta.
+
+procedure ph_deltamin (a, min_delta, b, npix)
+
+real a[ARB] # input vector
+real min_delta # minimum permitted absolute value
+real b[ARB] # output vector
+int npix # number of points
+
+int i
+
+begin
+ do i = 1, npix {
+ if (abs(a[i]) >= min_delta)
+ b[i] = a[i]
+ else if (a[i] < 0.0)
+ b[i] = -min_delta
+ else
+ b[i] = min_delta
+ }
+end