aboutsummaryrefslogtreecommitdiff
path: root/noao/twodspec/multispec/solve.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/twodspec/multispec/solve.x
downloadiraf-linux-fa080de7afc95aa1c19a6e6fc0e0708ced2eadc4.tar.gz
Initial commit
Diffstat (limited to 'noao/twodspec/multispec/solve.x')
-rw-r--r--noao/twodspec/multispec/solve.x312
1 files changed, 312 insertions, 0 deletions
diff --git a/noao/twodspec/multispec/solve.x b/noao/twodspec/multispec/solve.x
new file mode 100644
index 00000000..b7249242
--- /dev/null
+++ b/noao/twodspec/multispec/solve.x
@@ -0,0 +1,312 @@
+include "ms.h"
+
+# SOLVE:
+# Solve for the parameter correction vector using the banded matrix
+# technique decribed in Lawson and Hanson.
+#
+# The variables g, mdg, nb, ip, ir, mt, jt, rnorm, x and n have the
+# same meaning as described in Lawson and Hanson.
+
+procedure solve (ms, data, model, fitparams, profiles, ranges, len_line,
+ len_profile, nspectra, nparams, solution, norm)
+
+# Procedure parameters:
+pointer ms # MULTISPEC data structure
+real data[len_line] # Data to be fit
+real model[len_line] # Model to be corrected
+int fitparams[nspectra, nparams] # Model parameters to be fit
+real profiles[len_profile, nspectra, nparams]# Model parameter derivatives
+real ranges[nspectra, LEN_RANGES] # Ranges array for profiles
+int len_line # Length of data line
+int len_profile # Length of profiles
+int nspectra # Number of spectra
+int nparams # Number of model parameters
+real solution[nspectra, nparams] # Solution correction vector
+real norm # Measure of fit
+
+# Lawson and Hanson parameters:
+pointer g # Working array
+pointer x # Working vector
+int mdg # Maximum dimension of g
+int n # Number of parameters to be determined
+int nb # Parameter bandwith
+int ip, ir, mt, jt, jt_next # Array pointers
+real rnorm # Deviation from fit
+int ier # Error flag
+
+int ns # Maximum spectra bandwidth
+pointer columns # Columns to be used.
+int ncolumns # Number of columns
+pointer spectra # Spectra to be used.
+int nspectra_to_solve # Number of spectra
+int k_start, k_next # Indices to the spectra array
+int column, spectrum, parameter # Column, spectrum and parameter values
+int ns_in_band # Number of spectra in band
+int i, j, k, l, m
+bool is_zero
+pointer sp
+
+begin
+ # Determine columns, spectra, and parameters contributing to
+ # the solution matrix and the bandwidth of the matrix.
+ call smark (sp)
+ call salloc (columns, len_line, TY_INT)
+ call salloc (spectra, nspectra, TY_INT)
+ call band_set (ms, fitparams, data, profiles, ranges, Memi[columns],
+ Memi[spectra], len_line, len_profile, nspectra, nparams, ncolumns,
+ nspectra_to_solve, n, ns, nb)
+ if (n == 0) {
+ call sfree (sp)
+ return
+ }
+
+ # Allocate working memory for the Lawson and Hanson routines.
+ mdg = ncolumns
+ call salloc (g, mdg * (nb + 1), TY_REAL)
+ call salloc (x, n, TY_REAL)
+
+ # Initialize array indices.
+ ip = 1
+ ir = 1
+ jt = 1
+ mt = 0
+ jt_next = jt
+ k_next = 1
+
+ # Accumulate banded matrix for the specifed columns, spectra, and
+ # parameters.
+ do i = 1, ncolumns {
+ column = Memi[columns + i - 1]
+
+ k_start = k_next
+ j = jt
+ ns_in_band = 0
+ do k = k_start, nspectra_to_solve {
+ spectrum = Memi[spectra + k - 1]
+
+ # Evalute parameter derivatives and determine if all
+ # derivatives for the spectrum are zero.
+ is_zero = TRUE
+ do parameter = 1, nparams {
+ if (fitparams[spectrum, parameter] == NO)
+ next
+ j = j + 1
+ m = column - ranges[spectrum, X_START] + 1
+ if ((m < 1) || (m > len_profile))
+ Memr[x + j - 2] = 0.
+ else {
+ Memr[x + j - 2] = profiles[m, spectrum, parameter]
+ if (parameter != I0_INDEX)
+ Memr[x + j - 2] = Memr[x + j - 2] *
+ PARAMETER (ms, I0, spectrum)
+ if (Memr[x + j - 2] != 0.)
+ is_zero = FALSE
+ }
+ }
+
+ # If the spectrum has a non-zero contribution to the parameter
+ # matrix then increment the number of spectra in the
+ # band (ns_in_band).
+ # Else if the number of spectra in the band is still zero then
+ # increment the spectrum and parameter pointers.
+ # Else the band is assumed complete so break to accumulate
+ # the band.
+
+ if (!is_zero)
+ ns_in_band = ns_in_band + 1
+ else if (ns_in_band == 0) {
+ k_next = min (k + 1, nspectra_to_solve - ns + 1)
+ jt_next = min (j, n - nb + 1)
+ } else {
+ do l = j, jt_next + nb - 1
+ Memr[x + (l - 1)] = 0.
+ break
+ }
+ }
+
+ # If the number of spectra in the band is zero then reset the
+ # spectrum pointer (k_next) and go to the next column.
+ # Else if the number of spectra in the band exceeds the specified
+ # bandwidth return an error.
+ # Else accumulate the new band.
+
+ if (ns_in_band == 0) {
+ k_next = k_start
+ jt_next = jt
+ next
+ } else if (ns_in_band > ns)
+ call error (MS_ERROR, "Bandwidth too small")
+
+ # If a new submatrix is being started accumulate last submatrix.
+ if ((jt_next != jt) && (mt > 0)) {
+ call bndacc (Memr[g], mdg, nb, ip, ir, mt, jt)
+ mt = 0
+ }
+
+ # Increment the submatrix line pointer (mt) and add the band to
+ # submatrix being accumulated.
+
+ mt = mt + 1
+ jt = jt_next
+ do k = 1, nb
+ Memr[g+ir+mt-2 + (k-1)*mdg] = Memr[x + (jt - 1) + (k - 1)]
+ # INDEFR data may already be ignored in the column selection in
+ # band_set.
+ if (IS_INDEFR (data[column]))
+ Memr[g+ir+mt-2 + nb*mdg] = 0.
+ else
+ Memr[g+ir+mt-2 + nb*mdg] = data[column] - model[column]
+ }
+
+ # Accumulate last submatrix and calculate banded matrix solution vector.
+ call bndacc (Memr[g], mdg, nb, ip, ir, mt, jt)
+ call bndsol (1, Memr[g], mdg, nb, ip, ir, Memr[x], n, rnorm, ier)
+ if (ier != 0) {
+ call error (MS_ERROR, "bandsol: Solution error")
+ }
+
+ # Compute error matrix here. Not yet implemented.
+
+ # The solution from bndsol is in array x. Copy x to solution.
+ j = 0
+ do i = 1, nspectra_to_solve {
+ spectrum = Memi[spectra + i - 1]
+ do parameter = 1, nparams {
+ if (fitparams[spectrum, parameter] == YES) {
+ solution[spectrum, parameter] = Memr[x + j]
+ j = j + 1
+ } else
+ solution[spectrum, parameter] = 0.
+ }
+ }
+ norm = rnorm
+
+ call sfree (sp)
+end
+
+
+# Reject parameters which have only zero derivatives. Determine spectra,
+# columns, and number of parameters contributing to the solution.
+# Determine bandwidth of the banded matrix.
+
+procedure band_set (ms, fitparams, data, profiles, ranges, columns, spectra,
+ len_line, len_profile, nspectra, nparams, ncolumns, nspectra_to_solve,
+ n, ns, nb)
+
+pointer ms # MULTISPEC data structure
+int fitparams[nspectra, nparams] # Parameters to be fit
+real data[len_line] # Data being fit
+real profiles[len_profile, nspectra, nparams]# Parameter derivatives
+real ranges[nspectra, LEN_RANGES] # Ranges array for profiles
+int columns[len_line] # Return columns to be used
+int spectra[nspectra] # Return spectra to used
+int len_line # Length of data being fit
+int len_profile # Length of profiles
+int nspectra # Number of spectra
+int nparams # Number of parameters
+int ncolumns # Number of useful columns
+int nspectra_to_solve # Number of useful spectra
+int n # Number of parameters in fit
+int ns # Number of spectra in band
+int nb # Bandwith of matrix
+
+int i, j, k
+int column, spectrum, parameter
+int col_start
+real dx
+int xmin, xmax
+
+begin
+ # Initially set the spectra and columns to NO.
+ call amovki (NO, spectra, nspectra)
+ call amovki (NO, columns, len_line)
+
+ # Determine the spectra and columns in which the fitparams have
+ # non-zero derivatives. Flag those fitparams which do not have
+ # non-zero derivatives with NO. Count the number of parameters
+ # which have non-zero derivatives.
+
+ n = 0
+ do spectrum = 1, nspectra {
+ do parameter = 1, nparams {
+ if (fitparams[spectrum, parameter] == YES) {
+ fitparams[spectrum, parameter] = NO
+ col_start = ranges[spectrum, X_START]
+ do k = 1, len_profile {
+ if (profiles[k, spectrum, parameter] != 0.) {
+ column = col_start + k - 1
+ if ((column >= 1) && (column <= len_line)) {
+
+ # If the INDEFR data points are not to be
+ # ignored but replaced by the model in solve,
+ # replace the if clause with the following.
+ # columns[column] = YES
+ # fitparams[spectrum, parameter] = YES
+
+ if (!IS_INDEFR (data[column])) {
+ columns[column] = YES
+ fitparams[spectrum, parameter] = YES
+ }
+ }
+ }
+ }
+ if (fitparams[spectrum, parameter] == YES) {
+ n = n + 1
+ spectra[spectrum] = YES
+ }
+ }
+ }
+ }
+
+ # Count the number spectra to be used and set the spectra array.
+ nspectra_to_solve = 0
+ do spectrum = 1, nspectra {
+ if (spectra[spectrum] == YES) {
+ nspectra_to_solve = nspectra_to_solve + 1
+ spectra[nspectra_to_solve] = spectrum
+ }
+ }
+
+ # Count the number of columns to be used and set the columns array.
+ ncolumns = 0
+ do column = 1, len_line {
+ if (columns[column] == YES) {
+ ncolumns = ncolumns + 1
+ columns[ncolumns] = column
+ }
+ }
+
+ # Determine the maximum number spectra contributing to any column.
+ ns = 1
+ do i = 1, nspectra_to_solve - 1 {
+ xmax = 0
+ do parameter = 1, nparams {
+ if (fitparams[spectra[i], parameter] == YES)
+ xmax = max (xmax,
+ int (ranges[spectra[i], X_START] + len_profile - 1))
+ }
+ do j = i + 1, nspectra_to_solve {
+ xmin = len_line
+ do parameter = 1, nparams {
+ if (fitparams[spectra[j], parameter] == YES)
+ xmin = min (xmin, int (ranges[spectra[j], X_START]))
+ }
+ dx = xmax - xmin
+ if (dx < 0)
+ break
+ else
+ ns = max (ns, j - i + 1)
+ }
+ }
+
+ # Determine the banded matrix bandwidth.
+ nb = 0
+ do parameter = 1, nparams {
+ do i = 1, nspectra_to_solve {
+ if (fitparams[spectra[i], parameter] == YES) {
+ nb = nb + ns
+ break
+ }
+ }
+ }
+end