diff options
author | Joseph Hunkeler <jhunkeler@gmail.com> | 2015-07-08 20:46:52 -0400 |
---|---|---|
committer | Joseph Hunkeler <jhunkeler@gmail.com> | 2015-07-08 20:46:52 -0400 |
commit | fa080de7afc95aa1c19a6e6fc0e0708ced2eadc4 (patch) | |
tree | bdda434976bc09c864f2e4fa6f16ba1952b1e555 /noao/twodspec/apextract/approfile.x | |
download | iraf-linux-fa080de7afc95aa1c19a6e6fc0e0708ced2eadc4.tar.gz |
Initial commit
Diffstat (limited to 'noao/twodspec/apextract/approfile.x')
-rw-r--r-- | noao/twodspec/apextract/approfile.x | 765 |
1 files changed, 765 insertions, 0 deletions
diff --git a/noao/twodspec/apextract/approfile.x b/noao/twodspec/apextract/approfile.x new file mode 100644 index 00000000..eeb31a6d --- /dev/null +++ b/noao/twodspec/apextract/approfile.x @@ -0,0 +1,765 @@ +include <mach.h> +include <gset.h> +include <math/curfit.h> +include "apertures.h" + + +# AP_PROFILE -- Determine spectrum profile with pixel rejection. +# +# The profile is determined by dividing each dispersion point by an estimate +# of the spectrum and then smoothing and normalizing to unit integral. +# This routine has two algorithms (procedures) for smoothing, one for nearly +# aligned spectra and one for tilted spectra. The selection is determined +# by the calling program and signaled by whether there is a variation in +# the profile offsets. For both smoothing algorithms the same iterative +# rejection algorithm may be used to eliminate deviant points from affecting +# the profile. This rejection is selected by the "clean" parameter. +# A plot of the final profile along the dispersion may be made for the +# special plotfile "debugfits" or "debugall". +# +# Dispersion points with saturated pixels are ignored as well a when the +# total sky subtracted flux is negative. + +procedure ap_profile (im, ap, dbuf, nc, nl, c1, l1, sbuf, svar, profile, nx, ny, + xs, ys, asi) + +pointer im # IMIO pointer +pointer ap # Aperture structure +pointer dbuf # Data buffer +int nc, nl # Size of data buffer +int c1, l1 # Origin of data buffer +pointer sbuf # Sky values (NULL if none) +pointer svar # Sky variances +real profile[ny,nx] # Profile (returned) +int nx, ny # Size of profile array +int xs[ny], ys # Origin of profile array +pointer asi # Image interpolator for edge pixel weighting + +real gain # Gain +real rdnoise # Readout noise +real saturation # Maximum value for an unsaturated pixel +bool clean # Clean cosmic rays? +real lsigma, usigma # Rejection sigmas. + +int fd, ix, iy, ix1, ix2, xs1, xs2, nsum +int i, niterate, ixrej, iyrej, nrej, nreject +real p, s, chisq, tfac, rrej, predict, var0, var, vmin, resid, wt1, wt2, dat +pointer sp, str, spec, x1, x2, y, reject, xreject, data, sky, cv, gp + +int apgeti() +real apgetr(), ap_cveval(), apgimr() +bool apgetb() +errchk salloc, ap_horne, ap_marsh, apgimr, ap_asifit + +begin + # Allocate memory. Adjust pointers to be one indexed. + call smark (sp) + call salloc (str, SZ_LINE, TY_CHAR) + call salloc (spec, ny, TY_REAL) + call salloc (x1, ny, TY_REAL) + call salloc (x2, ny, TY_REAL) + call salloc (y, ny, TY_REAL) + call salloc (reject, nx*ny, TY_BOOL) + if (sbuf == NULL) { + call salloc (sky, nx, TY_REAL) + sky = sky - 1 + } + spec=spec-1; x1=x1-1; x2=x2-1; y=y-1 + + # Get task parameters. + gain = apgimr ("gain", im) + rdnoise = apgimr ("readnoise", im) ** 2 + saturation = apgetr ("saturation") + if (!IS_INDEF(saturation)) + saturation = saturation * gain + lsigma = apgetr ("lsigma") + usigma = apgetr ("usigma") + clean = apgetb ("clean") + if (clean) + niterate = apgeti ("niterate") + else + niterate = 0 + + # Initialize. + if (rdnoise == 0.) + vmin = 1. + else + vmin = rdnoise + if (sbuf == NULL) { + call aclrr (Memr[sky+1], nx) + var0 = rdnoise + } + cv = AP_CV(ap) + + # Set aperture limits and initialize rejection flags. + call alimi (xs, ny, xs1, xs2) + i = AP_AXIS(ap) + p = AP_CEN(ap,i) + AP_LOW(ap,i) + s = AP_CEN(ap,i) + AP_HIGH(ap,i) + xreject = reject + do iy = 1, ny { + dat = ap_cveval (cv, real (iy + ys - 1)) - c1 + 1 + Memr[x1+iy] = p + dat + Memr[x2+iy] = s + dat + Memr[x1+iy] = max (0.5, Memr[x1+iy]) + c1 - xs[iy] + Memr[x2+iy] = min (nc + 0.49, Memr[x2+iy]) + c1 - xs[iy] + ix1 = nint (Memr[x1+iy]) + ix2 = nint (Memr[x2+iy]) + Memr[y+iy] = iy + do ix = 1, nx { + if (ix < ix1 || ix > ix2) + Memb[xreject] = false + else + Memb[xreject] = true + xreject = xreject + 1 + } + } + + # Estimate spectrum by summing across the aperture with partial + # pixel estimates at the aperture edges. The initial profile + # estimates are obtained by normalizing by the spectrum estimate. + # Profiles where the spectrum is below sky are set to zero. + + call aclrr (profile, nx * ny) + nrej = 0 + do iy = 1, ny { + if (Memr[x1+iy] >= Memr[x2+iy]) { + Memr[spec+iy] = 0. + do ix = 1, nx + profile[iy,ix] = 0. + next + } + + call ap_asifit (dbuf+(iy+ys-1-l1)*nc, nc, xs[iy]-c1+1, + Memr[x1+iy]-c1+xs[iy], Memr[x2+iy]-c1+xs[iy], data, asi) + if (sbuf != NULL) + sky = sbuf + (iy - 1) * nx - 1 + call ap_edge (asi, Memr[x1+iy]+1, Memr[x2+iy]+1, wt1, wt2) + ix1 = nint (Memr[x1+iy]) + ix2 = nint (Memr[x2+iy]) + s = 0. + do ix = ix1, ix2 { + if (!IS_INDEF(saturation)) + if (Memr[data+ix] > saturation) { + s = 0. + nrej = nrej + 1 + break; + } + dat = Memr[data+ix] - Memr[sky+ix] + if (ix1 == ix2) + dat = wt1 * dat + else if (ix == ix1) + dat = wt1 * dat + else if (ix == ix2) + dat = wt2 * dat + s = s + dat + } + + if (s > 0.) { + do ix = ix1, ix2 + profile[iy,ix] = max (0., (Memr[data+ix]-Memr[sky+ix])/s) + } else { + do ix = ix1, ix2 + profile[iy,ix] = 0. + } + Memr[spec+iy] = s + } + + if (nrej == ny) + call error (1, "All profiles contain saturated pixels") + else if (nrej > 0) { + call sprintf (Memc[str], SZ_LINE, + "EXTRACT: %d profiles with saturated pixels in aperture %d") + call pargi (nrej) + call pargi (AP_ID(ap)) + if (nrej < ny / 3) + call ap_log (Memc[str], YES, NO, NO) + else + call ap_log (Memc[str], YES, NO, YES) + } + + # Smooth the profile and possibly reject deviant pixels. + nreject = 0 + tfac = 2. + do i = 0, niterate { + + # Estimate profile. + if (xs1 == xs2) + call ap_horne (im, cv, dbuf, nc, nl, c1, l1, Memr[spec+1], sbuf, + svar, Memb[reject], profile, nx, ny, xs, ys, + Memr[x1+1], Memr[x2+1]) + else + call ap_marsh (im, dbuf, nc, nl, c1, l1, Memr[spec+1], sbuf, + svar, Memb[reject], profile, nx, ny, xs, ys, + Memr[x1+1], Memr[x2+1]) + + if (i == niterate) + break + + # Reject pixels. The rejection threshold is based on the overall + # chi square. Pixels are rejected on the basis of the current + # chi square and the largest residual not rejected is compared + # against the final chi square to possibly trigger another round + # of rejections. + + chisq = 0.; nsum = 0; ixrej = 0; iyrej = 0; rrej = 0.; nrej = 0 + do iy = 1, ny { + s = Memr[spec+iy] + if (s <= 0.) + next + call ap_asifit (dbuf+(iy+ys-1-l1)*nc, nc, xs[iy]-c1+1, + Memr[x1+iy]-c1+xs[iy], Memr[x2+iy]-c1+xs[iy], data, asi) + if (sbuf != NULL) { + sky = sbuf + (iy - 1) * nx - 1 + var0 = rdnoise + Memr[svar+iy-1] + } + call ap_edge (asi, Memr[x1+iy]+1, Memr[x2+iy]+1, wt1, wt2) + xreject = reject + (iy - 1) * nx - 1 + ix1 = nint (Memr[x1+iy]) + ix2 = nint (Memr[x2+iy]) + do ix = ix1, ix2 { + if (Memb[xreject+ix]) { + nsum = nsum + 1 + predict = max (0., s * profile[iy,ix] + Memr[sky+ix]) + var = max (vmin, var0 + predict) + resid = (Memr[data+ix] - predict) / sqrt (var) + chisq = chisq + resid**2 + if (resid < -tfac*lsigma || resid > tfac*usigma) { + if (ix < ix1 || ix > ix2) + p = 0. + else if (ix1 == ix2) + p = wt1 + else if (ix == ix1) + p = wt1 + else if (ix == ix2) + p = wt2 + else + p = 1 + Memr[spec+iy] = Memr[spec+iy] - + p * (Memr[data+ix] - predict) + nrej = nrej + 1 + Memb[xreject+ix] = false + } else if (abs (resid) > abs (rrej)) { + rrej = resid + if (ix < ix1 || ix > ix2) + p = 0. + else if (ix1 == ix2) + p = wt1 + else if (ix == ix1) + p = wt1 + else if (ix == ix2) + p = wt2 + else + p = 1 + dat = p * (Memr[data+ix] - predict) + ixrej = ix + iyrej = iy + } + } + } + } + + if (nsum == 0) + call error (1, "All pixels rejected") + tfac = sqrt (chisq / nsum) + if (rrej < -tfac * lsigma || rrej > tfac * usigma) { + Memr[spec+iyrej] = Memr[spec+iyrej] - dat + xreject = reject + (iyrej - 1) * nx - 1 + Memb[xreject+ixrej] = false + nrej = nrej + 1 + } + + nreject = nreject + nrej + if (nrej == 0) + break + } + + # These plots are too big for production work but can be turned on + # for debugging. + + call ap_popen (gp, fd, "fits") + if (gp != NULL) { + ix1 = xs1 + ix2 = xs2 + nx - 1 + if (xs1 != xs2) { + ix1 = ix1 + 1 + ix2 = ix2 - 1 + } + do ix = ix1, ix2 { + nrej = 0 + do iy = 1, ny { + i = ix - xs[iy] + 1 + if (i < 1 || i > nx) + next + if (Memr[spec+iy] <= 0.) + next + data = dbuf + (iy + ys - 1 - l1) * nc + ix - c1 - 1 + if (sbuf != NULL) + s = Memr[sbuf+(iy-1)*nx+i-1] + else + s = Memr[sky+i] + nrej = nrej + 1 + Memr[y+nrej] = iy + ys - 1 + Memr[x1+nrej] = max (-.1, min (1.1, + (Memr[data+1] - s) / Memr[spec+iy])) + Memr[x2+nrej] = profile[iy,i] + } + call gclear (gp) + call gascale (gp, Memr[x1+1], nrej, 2) + call grscale (gp, Memr[x2+1], nrej, 2) + call gswind (gp, Memr[y+1], Memr[y+nrej], INDEF, INDEF) + if (AP_AXIS(ap) == 1) { + call sprintf (Memc[str], SZ_LINE, "Column %d") + call pargi (ix) + call glabax (gp, Memc[str], "Line", "Profile") + } else { + call sprintf (Memc[str], SZ_LINE, "Line %d") + call pargi (ix) + call glabax (gp, Memc[str], "Column", "Profile") + } + call gpmark (gp, Memr[y+1], Memr[x1+1], nrej, GM_POINT, 1., 1.) + call gpline (gp, Memr[y+1], Memr[x2+1], nrej) + } + } + call ap_pclose (gp, fd) + + # Log the number of rejected pixels. + if (clean) { + call sprintf (Memc[str], SZ_LINE, + "EXTRACT: %d pixels rejected for profile from aperture %d") + call pargi (nreject) + call pargi (AP_ID(ap)) + call ap_log (Memc[str], YES, NO, NO) + } + + call sfree (sp) +end + + +# AP_HORNE -- Determine profile by fitting a low order function parallel to +# dispersion along image lines or columns after dividing by a spectrum +# estimate. An initial profile estimate and a rejection array are +# required for setting the weights. This is a straightforward algorithm +# similar to images.fit1d except that it is noninteractive. The fitting +# function is fixed at a cubic spline and the number of pieces is set by +# the amount of tilt such that there is one cubic spline piece per +# passage across the tilted spectrum plus an amount based on the order +# of the tracing function. It is named after Keith Horne +# since this is what is outlined in his paper. The profile array is used +# cleverly to minimize memory requirements. The storage order of the +# profile array, which is transposed relative to the data, is determined +# by this procedure. + +procedure ap_horne (im, cvtrace, dbuf, nc, nl, c1, l1, spec, sbuf, svar, reject, + profile, nx, ny, xs, ys, x1, x2) + +pointer im # IMIO pointer +pointer cvtrace # Trace pointer +pointer dbuf # Data buffer +int nc, nl # Size of data buffer +int c1, l1 # Origin of data buffer +real spec[ny] # Spectrum estimate +pointer sbuf # Sky values (NULL if none) +pointer svar # Sky variances +bool reject[nx,ny] # Rejection flags +real profile[ny,nx] # Initial profile in, improved profile out +int nx, ny # Size of profile array +int xs[ny], ys # Origin of profile array +real x1[ny], x2[ny] # Aperture limits in profile array + +int cvtype # Curfit type +int order # Order of curfit function. +real rdnoise # Readout noise in RMS data numbers. + +int ix, iy, ierr +real p, s, sk, var, vmin, var0, wmin +pointer sp, y, w, cv, dbuf1, data, sky + +#int apgeti() +int cvstati() +real apgimr() +errchk salloc, apgimr + +begin + call smark (sp) + call salloc (y, ny, TY_REAL) + call salloc (w, ny, TY_REAL) + + # Get CL parameters + #cvtype = apgeti ("e_function") + #order = apgeti ("e_order") + rdnoise = apgimr ("readnoise", im) ** 2 + + # Initialize. + call alimr (x1, ny, p, s) + cvtype = SPLINE3 + order = int (s - p + 1) + max (0, cvstati (cvtrace, CVNCOEFF) - 2) + #order = min (20, order) + order = 2 * order + call cvinit (cv, cvtype, order, 1., real (ny)) + do iy = 1, ny + Memr[y+iy-1] = iy + if (rdnoise == 0.) + vmin = 1. + else + vmin = rdnoise + dbuf1 = dbuf + (ys - l1 - 1) * nc - c1 - 1 + if (sbuf == NULL) { + sk = 0. + var0 = rdnoise + } + + # For each line parallel to the dispersion divide by a spectrum + # estimate and then fit the smoothing function. Use the input + # profile and rejection array to set the weights. + + do ix = 1, nx { + data = dbuf1 + ix + if (sbuf != NULL) + sky = sbuf - nx - 1 + ix + wmin = MAX_REAL + do iy = 1, ny { + s = spec[iy] + if (s > 0. && reject[ix,iy]) { + if (sbuf != NULL) { + sk = Memr[sky+iy*nx] + var0 = rdnoise + Memr[svar+iy-1] + } + p = profile[iy,ix] + var = max (vmin, var0 + max (0., s * p + sk)) + var = (s ** 2) / var + wmin = min (wmin, var) + Memr[w+iy-1] = var + profile[iy,ix] = (Memr[data+iy*nc+xs[iy]] - sk) / s + } else + Memr[w+iy-1] = 0. + } + if (wmin == MAX_REAL) + call amovkr (1., Memr[w], ny) + else + call amaxkr (Memr[w], wmin / 10., Memr[w], ny) + call cvfit (cv, Memr[y], profile[1,ix], Memr[w], ny, WTS_USER, ierr) + call cvvector (cv, Memr[y], profile[1,ix], ny) + call amaxkr (profile[1,ix], 0., profile[1,ix], ny) + } + + call cvfree (cv) + call sfree (sp) +end + + +# AP_MARSH -- Determine profile by Marsh algorithm (PASP V101, P1032, 1989). +# This algorithm fits low order polynomials to weighted points sampled +# at uniform intervals parallel to the aperture trace. The polynomials +# are coupled through the weights and so requires a 2D matrix inversion. +# This is a relatively slow algorithm but does provide low order smoothing +# for arbitrary profile shapes in highly tilted spectra. An estimate +# of the profile, a rejection array, sky and sky variance, and aperture +# limit arrays are required. + +procedure ap_marsh (im, dbuf, nc, nl, c1, l1, spec, sbuf, svar, reject, + profile, nx, ny, xs, ys, x1, x2) + +pointer im # IMIO pointer +pointer dbuf # Data buffer +int nc, nl # Size of data buffer +int c1, l1 # Origin of data buffer +real spec[ny] # Spectrum estimate +pointer sbuf # Sky values (NULL if none) +pointer svar # Sky variances +bool reject[nx,ny] # Rejection flags +real profile[ny,nx] # Initial profile in, improved profile out +int nx, ny # Size of profile array +int xs[ny], ys # Origin of profile array +real x1[ny], x2[ny] # Aperture limits in profile array + +real spix # Polynomial pixel separation +int npols # Number of polynomials +int order # Order of function. +real rdnoise # Readout noise in RMS data numbers. + +int il, jl, kl, ll, ix, iy, ix1, ix2, nside, nadd +int ip, ip1, ip2, index1, index2, index3 +real p, s, s2, dat, sk, var, vmin, var0 +real dx0, dx1, dx2, dx3, dx4, xj, xk, xt, xz, qj, qk, xadd +double sum1, sum2 +pointer sp, work, work1, work2, work3, work4, ysum, data, sky + +int apgeti() +real apgetr(), apgimr() +errchk salloc, apgimr + +begin + # Get CL parameters + #npols = apgeti ("npols") + spix = apgetr ("polysep") + order = apgeti ("polyorder") + rdnoise = apgimr ("readnoise", im) ** 2 + + # Set dimensions. + npols = (x2[1] - x1[1] + 2) / spix + spix = (x2[1] - x1[1] + 2) / real (npols) + nside = npols * order + nadd = nside * nside + if (spix > 1.) + call error (4, "Polynomial separation too large") + + # Allocate memory. One index pointers. + call smark (sp) + call salloc (work, nadd+3*nside, TY_REAL) + call salloc (work4, nside, TY_INT) + call salloc (ysum, ny, TY_REAL) + work = work - 1 + work1 = work + nadd + work2 = work1 + nside + work3 = work2 + nside + work4 = work4 - 1 + ysum=ysum-1 + if (sbuf == NULL) { + call salloc (sky, nx, TY_REAL) + sky = sky - 1 + } + + # Initialize. + call aclrr (Memr[work+1], nadd+3*nside) + call aclri (Memi[work4+1], nside) + if (rdnoise == 0.) + vmin = 1. + else + vmin = rdnoise + if (sbuf == NULL) { + call aclrr (Memr[sky+1], nx) + var0 = rdnoise + } + + # Factors for weights. + dx0 = 0.5 - spix + dx1 = abs (dx0) + dx2 = 1. - (dx0 / spix) ** 2 + dx3 = 0.5 + spix + dx4 = sqrt (2.) * spix + + # Accumulate least terms for least squares matrix equation AX = B. + + # First accumulate B. + do jl = 0, npols-1 { + do iy = 1, ny { + if (spec[iy] <= 0.) + next + + xj = x1[iy] - 1 + spix * (real (jl) + 0.5) + ix1 = nint (xj - spix) + ix2 = nint (xj + spix) + if (ix1 < 1 || ix2 > nx) { + Memr[ysum+iy] = 0. + next + } + + data = dbuf + (iy + ys - 1 - l1) * nc + xs[iy] - c1 - 1 + if (sbuf != NULL) { + sky = sbuf + (iy - 1) * nx - 1 + var0 = rdnoise + Memr[svar+iy-1] + } + + # Evaluate qj, the contribution of polynomial number jl+1 + # for the pixel ix1,jj. Four cases are considered. The + # first two account for the triangular interpolation + # function partially overlapping a pixel, on one side + # only. The third is for the function wholly inside a + # pixel, and finally for the pixel wholly covered by the + # interpolation function. + + s = spec[iy] + sum1 = 0. + do ix = ix1, ix2 { + if (!reject[ix,iy]) + next + p = profile[iy,ix] + sk = Memr[sky+ix] + dat = Memr[data+ix] - sk + var = max (vmin, var0 + max (0., s * p + sk)) + + xz = xj - real (ix) + xt = abs (xz) + if (xt >= dx1) { + if (xt >= 0.5) + qj = ((xt - dx3) / dx4) ** 2 + else + qj = 1.- ((xt - dx0) / dx4) ** 2 + + } else if (xt <= dx0) + qj = 1. + else + qj = dx2 - (xz / spix) ** 2 + sum1 = sum1 + qj * s * dat / var + } + Memr[ysum+iy] = sum1 + } + + index1 = order * jl + do il = 1, order { + sum1 = 0. + ip = il - 1 + do iy = 1, ny + if (spec[iy] > 0.) + sum1 = sum1 + Memr[ysum+iy] * ((real (iy) / ny) ** ip) + Memr[work1+index1+il] = sum1 + } + } + + # Now accumulate matrix A. Since it is symmetric we only need to + # evaluate half of it. Since it is banded we only need to evaluate + # contribution if two polynomial terms can be affected by the same + # pixel. + + ip1 = nside - 1 + ip2 = order * ip1 + do jl = 0, npols-1 { + do kl = 0, jl { + if (spix * (jl - kl - 2) > 0.) + next + do iy = 1, ny { + if (spec[iy] <= 0.) + next + if (sbuf != NULL) { + sky = sbuf + (iy - 1) * nx - 1 + var0 = rdnoise + Memr[svar+iy-1] + } + + # Compute left and right limits of polynomials jl+1 + # and kl+1 for this value of y Evaluate sum over row + # of qj[jl+1] times qj[kl+1] where qj[i] is fraction + # of polynomial i which contributes to to pixel ix,jj. + + xj = x1[iy] - 1 + spix * (real (jl) + 0.5) + xk = x1[iy] - 1 + spix * (real (kl) + 0.5) + ix1 = nint (xj - spix) + ix2 = nint (xk + spix) + + if (ix2 < ix1 || ix1 < 1 || ix2 > nx) { + Memr[ysum+iy] = 0. + next + } + + s = spec[iy] + s2 = s * s + sum1 = 0. + do ix = ix1, ix2 { + if (reject[ix,iy]) { + p = profile[iy,ix] + sk = Memr[sky+ix] + var = max (vmin, var0 + max (0., s * p + sk)) + + xz = xj - real (ix) + xt = abs (xz) + if (xt >= dx1) { + if (xt >= 0.5) + qj = ((xt-dx3)/dx4)**2 + else + qj = 1.- ((xt-dx0)/dx4)**2 + } else if (xt <= dx0) + qj = 1. + else + qj = dx2 - (xz / spix) ** 2 + if (kl != jl) { + xz = xk - real (ix) + xt = abs (xz) + if (xt >= dx1) { + if (xt >= 0.5) + qk = ((xt-dx3)/dx4)**2 + else + qk = 1.-((xt-dx0)/dx4)**2 + } else if (xt <= dx0) + qk = 1. + else + qk = dx2 - (xz / spix) ** 2 + } else + qk = qj + sum1 = sum1 + qj * qk * s2 / var + } + } + Memr[ysum+iy] = sum1 + } + + do il = 1, order { + do ll = 1, il { + sum1 = 0. + ip = il + ll - 2 + do iy = 1, ny + if (spec[iy] > 0.) + sum1 = sum1 + + Memr[ysum+iy] * ((real (iy) / ny)**ip) + index1 = nside * (order*jl+il-1) + order * kl + ll + Memr[work+index1] = sum1 + if (ll != il) { + ip = ip1 * (ll - il) + index2 = index1 + ip + Memr[work+index2] = sum1 + } else + index2 = index1 + if (kl != jl) { + index3 = index2 + ip2 * (kl - jl) + Memr[work+index3] = sum1 + if (ll != il) + Memr[work+index3-ip] = sum1 + } + } + } + } + } + + # Solve matrix equation AX = B for X. A is a real symmetric, + # positive definite matrix, dimension (order*npols)**2. X is + # the vector representing the coefficients fitted to the + # normalized profile. Coefficients are reordered for later speed. + + call hfti (Memr[work+1], nside, nside, nside, Memr[work1+1], 1, 1, + 0.01, ip, p, Memr[work2+1], Memr[work3+1], Memi[work4+1]) + + do jl = 1, order { + do il = 1, npols { + index1 = order * (il - 1) + jl + index2 = npols * (jl - 1) + il + Memr[work+index2] = Memr[work1+index1] + } + } + + # Evaluate fit and make profile positive only. + do iy = 1, ny { + ix1 = nint (x1[iy]) + ix2 = nint (x2[iy]) + xadd = x1[iy] - 1 + s = 0. + do ix = 1, nx { + xj = real (ix) - xadd - 0.5 + xk = real (ix) - xadd + 0.5 + ip1 = int (xj / spix + 0.5) + ip2 = int (xk / spix + 1.5) + ip1 = max (1, min (ip1, npols)) + ip2 = max (1, min (ip2, npols)) + sum1 = 0. + do jl = 0, order-1 { + index1 = npols * jl + sum2 = 0. + do il = ip1, ip2 { + xz = xadd + spix * (real (il-1) + 0.5) - real (ix) + xt = abs (xz) + if (xt >= dx1) { + if (xt >= 0.5) + qj = ((xt - dx3) / dx4) ** 2 + else + qj = 1. - ((xt - dx0) / dx4) ** 2 + } else if (xt <= dx0) + qj = 1. + else + qj = dx2 - (xz / spix) ** 2 + sum2 = sum2 + qj * Memr[work+index1+il] + } + sum1 = sum1 + sum2 * ((real (iy)/ ny) ** jl) + } + profile[iy,ix] = max (0.d0, sum1) + } + } + + call sfree (sp) +end |