aboutsummaryrefslogtreecommitdiff
path: root/noao/onedspec/t_fitprofs.x
diff options
context:
space:
mode:
Diffstat (limited to 'noao/onedspec/t_fitprofs.x')
-rw-r--r--noao/onedspec/t_fitprofs.x1151
1 files changed, 1151 insertions, 0 deletions
diff --git a/noao/onedspec/t_fitprofs.x b/noao/onedspec/t_fitprofs.x
new file mode 100644
index 00000000..9aa389bc
--- /dev/null
+++ b/noao/onedspec/t_fitprofs.x
@@ -0,0 +1,1151 @@
+include <error.h>
+include <imhdr.h>
+include <smw.h>
+include <gset.h>
+include <ctotok.h>
+
+
+# Profile types.
+define PTYPES "|gaussian|lorentzian|voigt|"
+define GAUSS 1 # Gaussian profile
+define LORENTZ 2 # Lorentzian profile
+define VOIGT 3 # Voigt profile
+
+# Type of constraints.
+define FITTYPES "|fixed|single|all|"
+define FIXED 1 # Fixed parameter
+define SINGLE 2 # Fit a single value for all lines
+define INDEP 3 # Fit independent values for all lines
+
+# Elements of fit array.
+define BKG 1 # Background
+define POS 2 # Position
+define INT 3 # Intensity
+define GAU 4 # Gaussian FWHM
+define LOR 5 # Lorentzian FWHM
+
+# Output image options.
+define OPTIONS "|difference|fit|"
+define DIFF 1
+define FIT 2
+
+# Monte-Carlo errors
+define MC_N 50 # Monte-Carlo samples (overridden by users)
+define MC_P 10 # Percent done interval (percent)
+define MC_SIG 68 # Sigma sample point (percent)
+
+define NSUB 3 # Number of pixel subsamples
+
+
+# T_FITPROFS -- Fit image profiles.
+
+procedure t_fitprofs()
+
+int inlist # List of input spectra
+pointer aps # Aperture list
+pointer bands # Band list
+
+int ptype # Profile type
+pointer pg, xg, yg, sg, lg # Fitting region and initial components
+real gfwhm # Default gfwhm
+real lfwhm # Default lfwhm
+int fit[5] # Fit flags: background, position, gfwhm, lfwhm
+
+int nerrsample # Number of error samples to use
+real sigma0 # Constant noise
+real invgain # Inverse gain
+
+pointer components # List of components
+bool verbose # Verbose?
+int log # Log file
+int plot # Plot file
+int outlist # List of output spectra
+int option # Output image option
+bool clobber # Clobber existing images?
+bool merge # Merge with existing images?
+
+real x, y, g, l
+bool complement
+int i, p, ng, nalloc
+pointer sp, input, output, ptr
+
+real clgetr()
+bool clgetb()
+int clgeti(), clgwrd(), clscan()
+int imtopenp(), imtgetim(), imtlen()
+int open(), fscan(), nscan(), strdic(), nowhite()
+pointer rng_open()
+errchk open
+
+begin
+ call smark (sp)
+ call salloc (input, SZ_FNAME, TY_CHAR)
+ call salloc (output, SZ_FNAME, TY_CHAR)
+
+ # Get parameters.
+ inlist = imtopenp ("input")
+ outlist = imtopenp ("output")
+ if (imtlen (outlist) > 1 && imtlen (outlist) != imtlen (inlist))
+ call error (1, "Input and output image lists do not make sense")
+
+ verbose = clgetb ("verbose")
+ call clgstr ("logfile", Memc[output], SZ_FNAME)
+ if (nowhite (Memc[output], Memc[output], SZ_FNAME) == 0)
+ log = NULL
+ else
+ log = open (Memc[output], APPEND, TEXT_FILE)
+ call clgstr ("plotfile", Memc[output], SZ_FNAME)
+ if (nowhite (Memc[output], Memc[output], SZ_FNAME) == 0)
+ plot = NULL
+ else
+ plot = open (Memc[output], APPEND, BINARY_FILE)
+
+ ptype = clgwrd ("profile", Memc[output], SZ_FNAME, PTYPES)
+ gfwhm = clgetr ("gfwhm")
+ lfwhm = clgetr ("lfwhm")
+
+ if (clgetb ("fitbackground"))
+ fit[BKG] = SINGLE
+ else
+ fit[BKG] = FIXED
+ fit[POS] = clgwrd ("fitpositions", Memc[output], SZ_FNAME, FITTYPES)
+ fit[INT] = INDEP
+ fit[GAU] = clgwrd ("fitgfwhm", Memc[output], SZ_FNAME, FITTYPES)
+ fit[LOR] = clgwrd ("fitlfwhm", Memc[output], SZ_FNAME, FITTYPES)
+ option = clgwrd ("option", Memc[output], SZ_FNAME, OPTIONS)
+ clobber = clgetb ("clobber")
+ merge = clgetb ("merge")
+ nerrsample = clgeti ("nerrsample")
+ sigma0 = clgetr ("sigma0")
+ invgain = clgetr ("invgain")
+ if (IS_INDEF(sigma0) || IS_INDEF(invgain) || sigma0<0. || invgain<0.) {
+ sigma0 = INDEF
+ invgain = INDEF
+ }
+
+ # Get the initial positions/peak/ptype/gfwhm/lfwhm.
+ call clgstr ("positions", Memc[input], SZ_FNAME)
+ if (nowhite (Memc[input], Memc[input], SZ_FNAME) == 0) {
+ call sfree (sp)
+ call error (1, "A 'positions' file must be specified")
+ }
+ i = open (Memc[input], READ_ONLY, TEXT_FILE)
+ ng = 0
+ while (fscan (i) != EOF) {
+ call gargr (x)
+ call gargr (y)
+ call gargwrd (Memc[output], SZ_FNAME)
+ call gargr (g)
+ call gargr (l)
+ p = strdic (Memc[output], Memc[output], SZ_FNAME, PTYPES)
+ if (p == 0)
+ p = ptype
+ switch (nscan()) {
+ case 0:
+ next
+ case 1:
+ y = INDEF
+ p = ptype
+ g = gfwhm
+ l = lfwhm
+ case 2:
+ p = ptype
+ g = gfwhm
+ l = lfwhm
+ case 3:
+ g = gfwhm
+ l = lfwhm
+ case 4:
+ switch (p) {
+ case GAUSS:
+ l = lfwhm
+ case LORENTZ:
+ l = g
+ g = gfwhm
+ case VOIGT:
+ l = lfwhm
+ }
+ }
+
+ if (ng == 0) {
+ nalloc = 10
+ call malloc (pg, nalloc, TY_INT)
+ call malloc (xg, nalloc, TY_REAL)
+ call malloc (yg, nalloc, TY_REAL)
+ call malloc (sg, nalloc, TY_REAL)
+ call malloc (lg, nalloc, TY_REAL)
+ } else if (ng == nalloc) {
+ nalloc = nalloc + 10
+ call realloc (pg, nalloc, TY_INT)
+ call realloc (xg, nalloc, TY_REAL)
+ call realloc (yg, nalloc, TY_REAL)
+ call realloc (sg, nalloc, TY_REAL)
+ call realloc (lg, nalloc, TY_REAL)
+ }
+ switch (p) {
+ case GAUSS:
+ Memi[pg+ng] = p
+ Memr[xg+ng] = x
+ Memr[yg+ng] = y
+ Memr[sg+ng] = g
+ Memr[lg+ng] = 0.
+ case LORENTZ:
+ Memi[pg+ng] = p
+ Memr[xg+ng] = x
+ Memr[yg+ng] = y
+ Memr[sg+ng] = 0.
+ Memr[lg+ng] = g
+ case VOIGT:
+ Memi[pg+ng] = p
+ Memr[xg+ng] = x
+ Memr[yg+ng] = y
+ Memr[sg+ng] = g
+ Memr[lg+ng] = l
+ }
+ ng = ng + 1
+ }
+ call close (i)
+ if (ng == 0)
+ call error (1, "No profiles defined")
+
+ call realloc (xg, ng+2, TY_REAL)
+ call realloc (yg, ng+2, TY_REAL)
+ call realloc (sg, ng+2, TY_REAL)
+ call realloc (lg, ng+2, TY_REAL)
+
+ # Get fitting region and add to end of xg array.
+ i = clscan ("region")
+ call gargr (Memr[xg+ng])
+ call gargr (Memr[xg+ng+1])
+ if (i == EOF || nscan() < 1)
+
+ # Decode range strings and set complement if needed.
+ complement = false
+ call clgstr ("lines", Memc[input], SZ_FNAME)
+ ptr = input
+ if (Memc[ptr] == '!') {
+ complement = true
+ ptr = ptr + 1
+ }
+ iferr (aps = rng_open (Memc[ptr], INDEF, INDEF, INDEF))
+ call error (1, "Bad lines/column/aperture list")
+
+ call clgstr ("bands", Memc[input], SZ_FNAME)
+ ptr = input
+ if (Memc[ptr] == '!') {
+ complement = true
+ ptr = ptr + 1
+ }
+ iferr (bands = rng_open (Memc[ptr], INDEF, INDEF, INDEF))
+ call error (1, "Bad band list")
+
+ # Decode components.
+ call clgstr ("components", Memc[input], SZ_FNAME)
+ iferr (components = rng_open (Memc[input], INDEF, INDEF, INDEF))
+ call error (1, "Bad component list")
+
+ while (imtgetim (inlist, Memc[input], SZ_FNAME) != EOF) {
+ if (imtgetim (outlist, Memc[output], SZ_FNAME) == EOF)
+ Memc[output] = EOS
+
+ call fp_ms (Memc[input], aps, bands, complement, Memi[pg], Memr[xg],
+ Memr[yg], Memr[sg], Memr[lg], ng, fit, nerrsample,
+ sigma0, invgain, components, verbose, log, plot, Memc[output],
+ option, clobber, merge)
+ }
+
+ if (log != NULL)
+ call close (log)
+ if (plot != NULL)
+ call close (plot)
+ call rng_close (aps)
+ call rng_close (bands)
+ call rng_close (components)
+ call imtclose (inlist)
+ call imtclose (outlist)
+ call mfree (pg, TY_INT)
+ call mfree (xg, TY_REAL)
+ call mfree (yg, TY_REAL)
+ call mfree (sg, TY_REAL)
+ call mfree (lg, TY_REAL)
+ call sfree (sp)
+end
+
+
+# FP_MS -- Handle I/O and call fitting procedure.
+
+procedure fp_ms (input, aps, bands, complement, pg, xg, yg, sg, lg, ng, fit,
+ nerrsample, sigma0, invgain, components, verbose, log, plot, output,
+ option, clobber, merge)
+
+char input[ARB] # Input image
+pointer aps # Apertures
+pointer bands # Bands
+bool complement # Complement aperture selection
+
+int pg[ng] # Profile type
+real xg[ng] # Positions
+real yg[ng] # Peaks
+real sg[ng] # Gaussian FWHM
+real lg[ng] # Lorentzian FWHM
+int ng # Number of profiles
+int fit[5] # Fit flags
+
+int nerrsample # Number of error samples
+real sigma0 # Constant noise
+real invgain # Inverse gain
+
+pointer components # Output Component list
+bool verbose # Verbose output?
+int log # Log file descriptor
+int plot # Plot file descriptor
+char output[ARB] # Output image
+int option # Output image option
+bool clobber # Clobber existing image?
+bool merge # Merge with existing image?
+
+real aplow[2], aphigh[2]
+double a, b, w1, wb, dw, z, p1, p2, p3
+bool select
+int i, j, k, l, ap, beam, dtype, nw, ninaps, noutaps, nbands, naps, last
+int mwoutdim, axis[3]
+pointer ptr, in, out, tmp, mwin, mwout, sh, shout
+pointer sp, str, key, temp, ltm1, ltv1, ltm2, ltv2, coeff, outaps
+pointer model
+
+double shdr_lw()
+int imaccess(), imgnfn()
+bool streq(), strne(), rng_elementi(), fp_equald()
+pointer smw_openim(), mw_open()
+pointer immap(), imgl3r(), impl3r(), imofnlu()
+errchk immap, smw_openim, mw_open, shdr_open, imunmap, imgstr, imgl3r, impl3r
+errchk imdelete
+data axis/1,2,3/
+
+begin
+ call smark (sp)
+ call salloc (str, SZ_LINE, TY_CHAR)
+ call salloc (key, SZ_LINE, TY_CHAR)
+ call salloc (temp, SZ_FNAME, TY_CHAR)
+ call salloc (ltm1, 3*3, TY_DOUBLE)
+ call salloc (ltv1, 3, TY_DOUBLE)
+ call salloc (ltm2, 3*3, TY_DOUBLE)
+ call salloc (ltv2, 3, TY_DOUBLE)
+ coeff = NULL
+
+ # Initialize.
+ in = NULL; out = NULL; tmp = NULL
+ mwin = NULL; mwout = NULL
+ sh = NULL; shout = NULL
+ ninaps = 0; noutaps = 0; nbands = 0
+
+ iferr {
+ # Check for existing output image and abort if clobber is not set.
+ if (output[1] != EOS && imaccess (output, READ_ONLY) == YES) {
+ if (!clobber) {
+ call sprintf (Memc[str], SZ_LINE,
+ "Output spectrum %s already exists")
+ call pargstr (output)
+ call error (1, Memc[str])
+ } else if (merge) {
+ # Merging when the input and output are the same is a nop.
+ if (streq (input, output)) {
+ call sfree (sp)
+ return
+ }
+
+ # Open the output and check the type.
+ ptr = immap (output, READ_ONLY, 0); out = ptr
+ ptr = smw_openim (out); mwout = ptr
+ if (SMW_FORMAT(mwout) == SMW_ND) {
+ call sprintf (Memc[str], SZ_LINE, "%s - Wrong format")
+ call pargstr (output)
+ call error (1, Memc[str])
+ }
+
+ # Determine existing apertures.
+ noutaps = SMW_NSPEC(mwout)
+ nbands = SMW_NBANDS(mwout)
+ call salloc (outaps, noutaps, TY_INT)
+ do i = 1, noutaps {
+ call shdr_open (out, mwout, i, 1, INDEFI, SHHDR, sh)
+ Memi[outaps+i-1] = AP(sh)
+ }
+ }
+ call mktemp ("temp", Memc[temp], SZ_FNAME)
+ } else
+ call strcpy (output, Memc[temp], SZ_FNAME)
+
+ # Open the input and determine the number of final output
+ # apertures in order to set the output dimensions.
+
+ ptr = immap (input, READ_ONLY, 0); in = ptr
+ ptr = smw_openim (in); mwin = ptr
+
+ naps = noutaps
+
+ j = 1
+ if (SMW_FORMAT(mwin) != SMW_ND) {
+ j = 0
+ do i = 1, SMW_NBANDS(mwin) {
+ select = rng_elementi (bands, i)
+ if (!select)
+ next
+ j = j + 1
+ }
+ if (j == 0)
+ call error (1, "No bands selected in image")
+ }
+ nbands = max (j, nbands)
+
+ do i = 1, SMW_NSPEC(mwin) {
+ call shdr_open (in, mwin, i, 1, INDEFI, SHHDR, sh)
+ ap = AP(sh)
+ if (SMW_FORMAT(mwin) == SMW_ND) {
+ call smw_mw (mwin, i, 1, ptr, j, k)
+ select = rng_elementi (aps, j) && rng_elementi (bands, k)
+ } else
+ select = rng_elementi (aps, ap)
+
+ if ((complement && select) || (!complement && !select))
+ next
+ for (j=0; j<noutaps && Memi[outaps+j]!=ap; j=j+1)
+ ;
+ if (j == noutaps)
+ naps = naps + 1
+ ninaps = ninaps + 1
+ }
+ if (ninaps == 0) {
+ call sprintf (Memc[str], SZ_LINE, "No apertures selected in %s")
+ call pargstr (input)
+ call error (1, Memc[str])
+ }
+
+ # Set the output spectrum. For merging with an existing output
+ # copy to a temporary spectrum with size set appropriately.
+ # For a new output setup copy the input header, reset the
+ # physical line mapping, and clear all dispersion parameters.
+
+ if (out != NULL) {
+ ptr = immap (Memc[temp], NEW_COPY, out); tmp = ptr
+ if (IM_PIXTYPE(tmp) != TY_DOUBLE)
+ IM_PIXTYPE(tmp) = TY_REAL
+
+ IM_LEN(tmp,1) = max (SMW_LLEN(mwin,1), IM_LEN(out,1))
+ IM_LEN(tmp,2) = naps
+ IM_LEN(tmp,3) = max (nbands, IM_LEN(out,3))
+ if (nbands > 1)
+ IM_NDIM(tmp) = 3
+ else if (naps > 1)
+ IM_NDIM(tmp) = 2
+ else
+ IM_NDIM(tmp) = 1
+
+ do j = 1, IM_LEN(out,3)
+ do i = 1, IM_LEN(out,2) {
+ ptr = impl3r (tmp, i, j)
+ call aclrr (Memr[ptr], IM_LEN(tmp,1))
+ call amovr (Memr[imgl3r(out,i,j)], Memr[ptr], IM_LEN(out,1))
+ }
+ do j = 1, IM_LEN(out,3)
+ do i = IM_LEN(out,2)+1, IM_LEN(tmp,2) {
+ ptr = impl3r (tmp, i, j)
+ call aclrr (Memr[ptr], IM_LEN(tmp,1))
+ }
+ do j = IM_LEN(out,3)+1, nbands
+ do i = 1, IM_LEN(tmp,2) {
+ ptr = impl3r (tmp, i, j)
+ call aclrr (Memr[ptr], IM_LEN(tmp,1))
+ }
+ call imunmap (out)
+ out = tmp
+ tmp = NULL
+ } else if (Memc[temp] != EOS) {
+ ptr = immap (Memc[temp], NEW_COPY, in); out = ptr
+ if (IM_PIXTYPE(out) != TY_DOUBLE)
+ IM_PIXTYPE(out) = TY_REAL
+
+ # Set header
+ IM_LEN(out,1) = SMW_LLEN(mwin,1)
+ IM_LEN(out,2) = naps
+ IM_LEN(out,3) = nbands
+ if (nbands > 1)
+ IM_NDIM(out) = 3
+ else if (naps > 1)
+ IM_NDIM(out) = 2
+ else
+ IM_NDIM(out) = 1
+ mwoutdim = IM_NDIM(out)
+
+ j = imofnlu (out, "DISPAXIS,APID*,BANDID*")
+ while (imgnfn (j, Memc[key], SZ_LINE) != EOF)
+ call imdelf (out, Memc[key])
+ call imcfnl (j)
+
+ i = SMW_PDIM(mwin)
+ j = SMW_PAXIS(mwin,1)
+
+ ptr = mw_open (NULL, mwoutdim); mwout = ptr
+ call mw_newsystem (mwout, "equispec", mwoutdim)
+ call mw_swtype (mwout, axis, mwoutdim, "linear", "")
+ if (LABEL(sh) != EOS)
+ call mw_swattrs (mwout, 1, "label", LABEL(sh))
+ if (UNITS(sh) != EOS)
+ call mw_swattrs (mwout, 1, "units", UNITS(sh))
+
+ call mw_gltermd (SMW_MW(mwin,0), Memd[ltm1], Memd[ltv1], i)
+ call mw_gltermd (mwout, Memd[ltm2], Memd[ltv2], mwoutdim)
+ Memd[ltv2] = Memd[ltv1+(j-1)]
+ Memd[ltm2] = Memd[ltm1+(i+1)*(j-1)]
+ call mw_sltermd (mwout, Memd[ltm2], Memd[ltv2], mwoutdim)
+ call smw_open (mwout, NULL, out)
+ }
+
+ if (out != NULL) {
+ # Check dispersion function compatibility
+ # Nonlinear functions can be copied to different physical
+ # coordinate system though the linear dispersion can be
+ # modified.
+
+ call mw_gltermd (SMW_MW(mwout,0), Memd[ltm2], Memd[ltv2], mwoutdim)
+ a = Memd[ltv2]
+ b = Memd[ltm2]
+ if (DC(sh) == DCFUNC) {
+ i = SMW_PDIM(mwin)
+ j = SMW_PAXIS(mwin,1)
+
+ call mw_gltermd (SMW_MW(mwin,0), Memd[ltm1], Memd[ltv1], i)
+ Memd[ltv1] = Memd[ltv1+(j-1)]
+ Memd[ltm1] = Memd[ltm1+(i+1)*(j-1)]
+ if (!fp_equald (a,Memd[ltv1]) || !fp_equald (b,Memd[ltm1])) {
+ call error (1,
+ "Physical basis for nonlinear dispersion functions don't match")
+ }
+ }
+ }
+
+ # Now do the actual fitting
+ call salloc (model, SMW_LLEN(mwin,1), TY_REAL)
+ last = noutaps
+ do i = 1, SMW_NSPEC(mwin) {
+ call shdr_open (in, mwin, i, 1, INDEFI, SHHDR, sh)
+
+ # Check apertures.
+ ap = AP(sh)
+ if (SMW_FORMAT(mwin) == SMW_ND) {
+ call smw_mw (mwin, i, 1, ptr, j, k)
+ select = rng_elementi (aps, j) && rng_elementi (bands, k)
+ } else
+ select = rng_elementi (aps, ap)
+
+ if ((complement && select) || (!complement && !select))
+ next
+
+ call fp_title (sh, Memc[str], verbose, log)
+
+ call shdr_open (in, mwin, i, 1, INDEFI, SHDATA, sh)
+ if (SN(sh) < SMW_LLEN(mwin,1))
+ call aclrr (Memr[model], SMW_LLEN(mwin,1))
+ iferr (call fp_fit (sh, Memr[SX(sh)], Memr[SY(sh)], SN(sh), pg,
+ xg, yg, sg, lg, ng, fit, nerrsample, sigma0, invgain,
+ components, verbose, log, plot, Memc[str], Memr[model])) {
+ call erract (EA_WARN)
+ }
+
+ if (out != NULL) {
+ for (j=0; j<noutaps && Memi[outaps+j]!=ap; j=j+1)
+ ;
+
+ # Set output logical and physical lines
+ if (j < noutaps)
+ l = j + 1
+ else {
+ l = last + 1
+ last = l
+ }
+
+ # Copy and adjust dispersion info
+ call smw_gwattrs (mwin, i, 1, AP(sh), beam,
+ dtype, w1, dw, nw, z, aplow, aphigh, coeff)
+
+ w1 = shdr_lw (sh, 1D0)
+ wb = shdr_lw (sh, double (SN(sh)))
+ p1 = (NP1(sh) - a) / b
+ p2 = (NP2(sh) - a) / b
+ p3 = (IM_LEN(out,1) - a) / b
+ nw = nint (min (max (p1 ,p3), max (p1 ,p2))) + NP1(sh) - 1
+ if (p1 != p2)
+ dw = (wb - w1) / (p2 - p1) * (1 + z)
+ w1 = w1 * (1 + z) - (p1 - 1) * dw
+
+ call smw_swattrs (mwout, l, 1, ap, beam, dtype,
+ w1, dw, nw, z, aplow, aphigh, Memc[coeff])
+
+ # Copy titles
+ call smw_sapid (mwout, l, 1, TITLE(sh))
+ if (Memc[SID(sh,1)] != EOS)
+ call imastr (out, "BANDID1", Memc[SID(sh,1)])
+
+ # Copy the data
+ switch (option) {
+ case DIFF:
+ call asubr (Memr[SY(sh)], Memr[model],
+ Memr[impl3r(out,l,1)+NP1(sh)-1], SN(sh))
+ case FIT:
+ call amovr (Memr[model], Memr[impl3r(out,l,1)+NP1(sh)-1],
+ SN(sh))
+ }
+
+ # Verify copy
+ if (verbose) {
+ call shdr_open (out, mwout, l, 1, INDEFI, SHHDR, shout)
+ call printf ("%s%s(%d) --> %s%s(%s)\n")
+ call pargstr (IMNAME(sh))
+ call pargstr (IMSEC(sh))
+ call pargi (AP(sh))
+ call pargstr (IMNAME(shout))
+ call pargstr (IMSEC(shout))
+ call pargi (AP(shout))
+ call flush (STDOUT)
+ }
+ }
+ }
+
+ call smw_close (MW(sh))
+ if (out != NULL) {
+ call smw_saveim (mwout, out)
+ if (shout != NULL)
+ call smw_close (MW(shout))
+ call imunmap (out)
+ if (strne (Memc[temp], output)) {
+ call imdelete (output)
+ call imrename (Memc[temp], output)
+ }
+ }
+ call imunmap (in)
+ } then {
+ if (shout != NULL)
+ call smw_close (MW(shout))
+ else if (mwout != NULL)
+ call smw_close (mwout)
+ if (sh != NULL)
+ call smw_close (MW(sh))
+ else if (mwin != NULL)
+ call smw_close (mwin)
+ if (tmp != NULL)
+ call imunmap (tmp)
+ if (out != NULL)
+ call imunmap (out)
+ if (in != NULL)
+ call imunmap (in)
+ call erract (EA_WARN)
+ }
+
+ call shdr_close (shout)
+ call shdr_close (sh)
+ call mfree (coeff, TY_CHAR)
+ call sfree (sp)
+end
+
+
+define SQ2PI 2.5066283
+
+# FP_FIT -- Fit profile functions
+
+procedure fp_fit (sh, x, y, n, ptypes, pos, peaks, gfwhms, lfwhms, ng, fit,
+ nerrsample, sigma0, invgain, components, verbose, log, plot, title, mod)
+
+pointer sh # Spectrum data structure
+real x[n] # Coordinates
+real y[n] # Data
+int n # Number of data points
+
+int ptypes[ARB] # Profile types
+real pos[ARB] # Fitting region and initial positions
+real peaks[ARB] # Peak values
+real gfwhms[ARB] # Background levels and initial gfwhm
+real lfwhms[ARB] # Initial lfwhm
+int ng # Number of gaussian components
+
+int fit[5] # Fit flags
+
+int nerrsample # Number of error samples
+real sigma0 # Constant noise
+real invgain # Inverse gain
+
+pointer components # Component list
+bool verbose # Output to STDOUT?
+int log # Log file descriptor
+int plot # Plot file descriptor
+char title[ARB] # Plot title
+real mod[n] # Model
+
+int i, j, k, i1, i2, nfit, nsub, mc_n, mc_p, mc_sig
+long seed
+real xc, x1, x2, dx, y1, dy, z1, dz, w, z, scale, sscale
+real peak, flux, cont, gfwhm, lfwhm, eqw, chisq
+real flux1, cont1, eqw1, wyc1, slope1, v, u
+bool doerr
+pointer sp, str, xd, yd, sd, xg, yg, sg, lg, pg, yd1, xg1, yg1, sg1, lg1
+pointer ym, conte, xge, yge, sge, lge, fluxe, eqwe
+pointer gp, gopen()
+bool rng_elementi()
+real model(), gasdev(), asumr()
+double shdr_lw(), shdr_wl
+errchk fp_background, dofit, dorefit
+
+begin
+ # Determine fitting region.
+ x1 = pos[ng+1]
+ x2 = pos[ng+2]
+ i1 = nint (shdr_wl (sh, double(x1)))
+ i2 = nint (shdr_wl (sh, double(x2)))
+ i = min (n, max (i1, i2))
+ i1 = max (1, min (i1, i2))
+ i2 = i
+ nfit = i2 - i1 + 1
+ if (nfit < 3) {
+ call aclrr (mod, n)
+ call error (1, "Too few data points in fitting region")
+ }
+ x1 = shdr_lw (sh, double(i1))
+ x2 = shdr_lw (sh, double(i2))
+
+ # Allocate memory.
+ call smark (sp)
+ call salloc (str, SZ_LINE, TY_CHAR)
+ call salloc (xd, nfit, TY_REAL)
+ call salloc (yd, nfit, TY_REAL)
+ call salloc (sd, nfit, TY_REAL)
+ call salloc (xg, ng, TY_REAL)
+ call salloc (yg, ng, TY_REAL)
+ call salloc (sg, ng, TY_REAL)
+ call salloc (lg, ng, TY_REAL)
+ call salloc (pg, ng, TY_INT)
+
+ # Subtract the continuum and scale the data.
+ call fp_background (sh, x, y, n, x1, x2, y1, dy)
+ scale = 0.
+ doerr = !IS_INDEF(sigma0)
+ do i = i1, i2 {
+ Memr[xd+i-i1] = x[i]
+ Memr[yd+i-i1] = y[i] - (y1 + dy * (x[i]-x1))
+ if (y[i] <= 0.)
+ doerr = false
+ scale = max (scale, abs (Memr[yd+i-i1]))
+ }
+ if (doerr) {
+ do i = i1, i2
+ Memr[sd+i-i1] = sqrt (sigma0 ** 2 + invgain * y[i])
+ sscale = asumr (Memr[sd], nfit) / nfit
+ } else {
+ call amovkr (1., Memr[sd], nfit)
+ sscale = 1.
+ }
+ call adivkr (Memr[yd], scale, Memr[yd], nfit)
+ call adivkr (Memr[sd], sscale, Memr[sd], nfit)
+ y1 = y1 / scale
+ dy = dy / scale
+
+ # Setup initial estimates.
+ do i = 1, ng {
+ Memr[xg+i-1] = pos[i]
+ Memr[sg+i-1] = gfwhms[i]
+ Memr[lg+i-1] = lfwhms[i]
+ Memi[pg+i-1] = ptypes[i]
+ if (IS_INDEF(peaks[i])) {
+ j = max (1, min (nfit, nint (shdr_wl(sh,double(pos[i])))-i1+1))
+ Memr[yg+i-1] = Memr[yd+j-1]
+ } else
+ Memr[yg+i-1] = peaks[i] / scale
+ }
+ z1 = 0.
+ dz = 0.
+ dx = (x[n] - x[1]) / (n - 1)
+ nsub = NSUB
+ call dofit (fit, Memr[xd], Memr[yd], Memr[sd],
+ nfit, dx, nsub, z1, dz, Memr[xg], Memr[yg], Memr[sg],
+ Memr[lg], Memi[pg], ng, chisq)
+
+ # Compute Monte-Carlo errors.
+ mc_n = nerrsample
+ mc_p = nint (mc_n * MC_P / 100.)
+ mc_sig = nint (mc_n * MC_SIG / 100.)
+ if (doerr && mc_sig > 9) {
+ call salloc (yd1, nfit, TY_REAL)
+ call salloc (ym, nfit, TY_REAL)
+ call salloc (xg1, ng, TY_REAL)
+ call salloc (yg1, ng, TY_REAL)
+ call salloc (sg1, ng, TY_REAL)
+ call salloc (lg1, ng, TY_REAL)
+ call salloc (conte, mc_n*ng, TY_REAL)
+ call salloc (xge, mc_n*ng, TY_REAL)
+ call salloc (yge, mc_n*ng, TY_REAL)
+ call salloc (sge, mc_n*ng, TY_REAL)
+ call salloc (lge, mc_n*ng, TY_REAL)
+ call salloc (fluxe, mc_n*ng, TY_REAL)
+ call salloc (eqwe, mc_n*ng, TY_REAL)
+ do i = 1, nfit {
+ w = Memr[xd+i-1]
+ Memr[ym+i-1] = model (w, dx, nsub, Memr[xg], Memr[yg],
+ Memr[sg], Memr[lg], Memi[pg], ng)
+ }
+ seed = 1
+ do i = 0, mc_n-1 {
+ do j = 1, nfit
+ Memr[yd1+j-1] = Memr[ym+j-1] +
+ sscale / scale * Memr[sd+j-1] * gasdev (seed)
+ wyc1 = z1
+ slope1 = dz
+ call amovr (Memr[xg], Memr[xg1], ng)
+ call amovr (Memr[yg], Memr[yg1], ng)
+ call amovr (Memr[sg], Memr[sg1], ng)
+ call amovr (Memr[lg], Memr[lg1], ng)
+ call dorefit (fit, Memr[xd], Memr[yd1], Memr[sd],
+ nfit, dx, nsub, wyc1, slope1,
+ Memr[xg1], Memr[yg1], Memr[sg1],
+ Memr[lg1], Memi[pg], ng, chisq)
+
+ do j = 0, ng-1 {
+ cont = y1 + z1 + (dy + dz) * Memr[xg+j] - dy * x1
+ cont1 = y1 + wyc1 + (dy + slope1) * Memr[xg+j] - dy * x1
+ switch (Memi[pg+j]) {
+ case GAUSS:
+ flux = 1.064467 * Memr[yg+j] * Memr[sg+j]
+ flux1 = 1.064467 * Memr[yg1+j] * Memr[sg1+j]
+ case LORENTZ:
+ flux = 1.570795 * Memr[yg+j] * Memr[lg+j]
+ flux1 = 1.570795 * Memr[yg1+j] * Memr[lg1+j]
+ case VOIGT:
+ call voigt (0., 0.832555*Memr[lg+j]/Memr[sg+j], v, u)
+ flux = 1.064467 * Memr[yg+j] * Memr[sg+j] / v
+ call voigt (0., 0.832555*Memr[lg1+j]/Memr[sg1+j], v, u)
+ flux1 = 1.064467 * Memr[yg1+j] * Memr[sg1+j] / v
+ }
+ if (cont > 0. && cont1 > 0.) {
+ eqw = -flux / cont
+ eqw1 = -flux1 / cont1
+ } else {
+ eqw = 0.
+ eqw1 = 0.
+ }
+ Memr[conte+j*mc_n+i] = abs (cont1 - cont)
+ Memr[xge+j*mc_n+i] = abs (Memr[xg1+j] - Memr[xg+j])
+ Memr[yge+j*mc_n+i] = abs (Memr[yg1+j] - Memr[yg+j])
+ Memr[sge+j*mc_n+i] = abs (Memr[sg1+j] - Memr[sg+j])
+ Memr[lge+j*mc_n+i] = abs (Memr[lg1+j] - Memr[lg+j])
+ Memr[fluxe+j*mc_n+i] = abs (flux1 - flux)
+ Memr[eqwe+j*mc_n+i] = abs (eqw1 - eqw)
+ }
+ }
+ do j = 0, ng-1 {
+ call asrtr (Memr[conte+j*mc_n], Memr[conte+j*mc_n], mc_n)
+ call asrtr (Memr[xge+j*mc_n], Memr[xge+j*mc_n], mc_n)
+ call asrtr (Memr[yge+j*mc_n], Memr[yge+j*mc_n], mc_n)
+ call asrtr (Memr[sge+j*mc_n], Memr[sge+j*mc_n], mc_n)
+ call asrtr (Memr[lge+j*mc_n], Memr[lge+j*mc_n], mc_n)
+ call asrtr (Memr[fluxe+j*mc_n], Memr[fluxe+j*mc_n], mc_n)
+ call asrtr (Memr[eqwe+j*mc_n], Memr[eqwe+j*mc_n], mc_n)
+ }
+ call amulkr (Memr[conte], scale, Memr[conte], mc_n*ng)
+ call amulkr (Memr[yge], scale, Memr[yge], mc_n*ng)
+ call amulkr (Memr[fluxe], scale, Memr[fluxe], mc_n*ng)
+ }
+
+ call amulkr (Memr[yg], scale, Memr[yg], ng)
+ y1 = (y1 + z1 + dz * x1) * scale
+ dy = (dy + dz) * scale
+
+ # Log computed values
+ call sprintf (Memc[str], SZ_LINE,
+ "# Nfit=%d, background=%b, positions=%s, gfwhm=%s, lfwhm=%s\n")
+ call pargi (ng)
+ call pargb (fit[BKG] == SINGLE)
+ if (fit[POS] == FIXED)
+ call pargstr ("fixed")
+ else if (fit[POS] == SINGLE)
+ call pargstr ("single")
+ else
+ call pargstr ("all")
+ if (fit[GAU] == FIXED)
+ call pargstr ("fixed")
+ else if (fit[GAU] == SINGLE)
+ call pargstr ("single")
+ else
+ call pargstr ("all")
+ if (fit[LOR] == FIXED)
+ call pargstr ("fixed")
+ else if (fit[LOR] == SINGLE)
+ call pargstr ("single")
+ else
+ call pargstr ("all")
+ if (log != NULL)
+ call fprintf (log, Memc[str])
+ if (verbose)
+ call printf (Memc[str])
+ call sprintf (Memc[str], SZ_LINE, "# %8s%10s%10s%10s%10s%10s%10s\n")
+ call pargstr ("center")
+ call pargstr ("cont")
+ call pargstr ("flux")
+ call pargstr ("eqw")
+ call pargstr ("core")
+ call pargstr ("gfwhm")
+ call pargstr ("lfwhm")
+ if (log != NULL)
+ call fprintf (log, Memc[str])
+ if (verbose)
+ call printf (Memc[str])
+ do i = 1, ng {
+ if (!rng_elementi (components, i))
+ next
+ xc = Memr[xg+i-1]
+ cont = y1 + dy * (xc - x1)
+ peak = Memr[yg+i-1]
+ gfwhm = Memr[sg+i-1]
+ lfwhm = Memr[lg+i-1]
+ switch (Memi[pg+i-1]) {
+ case 1:
+ flux = 1.064467 * peak * gfwhm
+ case 2:
+ flux = 1.570795 * peak * lfwhm
+ case 3:
+ call voigt (0., 0.832555*lfwhm/gfwhm, v, u)
+ flux = 1.064467 * peak * gfwhm / v
+ }
+
+ if (cont > 0.)
+ eqw = -flux / cont
+ else
+ eqw = INDEF
+
+ call sprintf (Memc[str], SZ_LINE,
+ " %9.7g %9.7g %9.6g %9.4g %9.6g %9.4g %9.4g\n")
+ call pargr (xc)
+ call pargr (cont)
+ call pargr (flux)
+ call pargr (eqw)
+ call pargr (peak)
+ call pargr (gfwhm)
+ call pargr (lfwhm)
+ if (log != NULL)
+ call fprintf (log, Memc[str])
+ if (verbose)
+ call printf (Memc[str])
+ if (doerr && mc_sig > 9) {
+ call sprintf (Memc[str], SZ_LINE,
+ " (%7.7g) (%7.7g) (%7.6g) (%7.4g) (%7.6g) (%7.4g) (%7.4g)\n")
+ call pargr (Memr[xge+(i-1)*mc_n+mc_sig])
+ call pargr (Memr[conte+(i-1)*mc_n+mc_sig])
+ call pargr (Memr[fluxe+(i-1)*mc_n+mc_sig])
+ call pargr (Memr[eqwe+(i-1)*mc_n+mc_sig])
+ call pargr (Memr[yge+(i-1)*mc_n+mc_sig])
+ call pargr (Memr[sge+(i-1)*mc_n+mc_sig])
+ call pargr (Memr[lge+(i-1)*mc_n+mc_sig])
+ if (log != NULL)
+ call fprintf (log, Memc[str])
+ if (verbose)
+ call printf (Memc[str])
+ }
+ }
+
+ # Compute model.
+ call aclrr (mod, n)
+ do i = 0, ng-1 {
+ if (!rng_elementi (components, i+1))
+ next
+ do j = 1, n
+ #mod[j] = model (x[j], dx, nsub, Memr[xg+i], Memr[yg+i],
+ # Memr[sg+i], Memr[lg+i], Memi[pg+i], ng)
+ mod[j] = mod[j] + model (x[j], dx, nsub, Memr[xg+i], Memr[yg+i],
+ Memr[sg+i], Memr[lg+i], Memi[pg+i], 1)
+ }
+
+ # Draw graphs
+ if (plot != NULL) {
+ gp = gopen ("stdvdm", NEW_FILE, plot)
+ call gascale (gp, y[i1], nfit, 2)
+ call asubr (y[i1], mod[i1], Memr[yd], nfit)
+ call grscale (gp, Memr[yd], nfit, 2)
+ do i = i1, i2
+ Memr[yd+i-i1] = mod[i] + y1 + dy * (x[i] - x1)
+ call grscale (gp, Memr[yd], nfit, 2)
+ call gswind (gp, x1, x2, INDEF, INDEF)
+ call glabax (gp, title, "", "")
+ call gseti (gp, G_PLTYPE, 1)
+ call gpline (gp, Memr[xd], y[i1], nfit)
+ call gseti (gp, G_PLTYPE, 2)
+ call gpline (gp, Memr[xd], Memr[yd], nfit)
+ call gline (gp, x1, y1, x2, y1+dy*(x2-x1))
+ call gseti (gp, G_PLTYPE, 3)
+ call asubr (y[i1], mod[i1], Memr[yd], nfit)
+ call gpline (gp, Memr[xd], Memr[yd], nfit)
+ call gseti (gp, G_PLTYPE, 4)
+ do i = 0, ng-1 {
+ if (!rng_elementi (components, i+1))
+ next
+ k = 0
+ do j = i1, i2 {
+ w = x[j]
+ z = model (w, dx, nsub, Memr[xg+i], Memr[yg+i],
+ Memr[sg+i], Memr[lg+i], Memi[pg+i], 1)
+ z = z + y1 + dy * (w - x1)
+ if (k == 0) {
+ call gamove (gp, w, z)
+ k = 1
+ } else
+ call gadraw (gp, w, z)
+ }
+ }
+ call gclose (gp)
+ }
+
+ call sfree (sp)
+end
+
+
+# FP_BACKGROUND -- Iniital background.
+
+procedure fp_background (sh, x, y, n, x1, x2, y1, dy)
+
+pointer sh #I Spectrum pointer
+real x[n] #I Coordinate values
+real y[n] #I Data
+int n #I Number of data points
+real x1, x2 #I Fit endpoints
+real y1, dy #O Background
+
+int i, j, k, m, func
+real xval[2], yval[2]
+double z1, z2, z3
+pointer sp, bkg, str
+
+int ctotok(), ctor(), ctod(), strdic(), nscan()
+real asumr(), amedr()
+double shdr_wl(), shdr_lw()
+
+define err_ 10
+
+begin
+ call smark (sp)
+ call salloc (bkg, SZ_LINE, TY_CHAR)
+ call salloc (str, SZ_LINE, TY_CHAR)
+
+ xval[1] = x1
+ xval[2] = x2
+
+ call clgstr ("background", Memc[bkg], SZ_LINE)
+ call sscan (Memc[bkg])
+ do j = 1, 2 {
+ call gargwrd (Memc[bkg], SZ_LINE)
+ if (nscan() != j) {
+ i = max (1, min (n, nint (shdr_wl (sh, double(xval[j])))))
+ xval[j] = shdr_lw (sh, double(i))
+ yval[j] = y[i]
+ next
+ }
+
+ k = 1
+ if (ctor (Memc[bkg], k, yval[j]) == 0) {
+ if (ctotok (Memc[bkg], k, Memc[str], SZ_LINE) != TOK_IDENTIFIER)
+ goto err_
+ func = strdic (Memc[str], Memc[str], SZ_LINE, "|avg|med|")
+ if (func == 0)
+ goto err_
+ k = k + 1
+ if (ctod (Memc[bkg], k, z1) == 0)
+ goto err_
+ k = k + 1
+ if (ctod (Memc[bkg], k, z2) == 0)
+ goto err_
+ k = k + 1
+ if (ctod (Memc[bkg], k, z3) == 0)
+ z3 = 1
+
+ z1 = shdr_wl (sh, z1)
+ z2 = shdr_wl (sh, z2)
+ i = max (1, nint(min(z1,z2)))
+ m = min (n, nint(max(z1,z2))) - i + 1
+ if (m < 1)
+ goto err_
+
+ # This is included to eliminate an optimizer bug on solaris.
+ call sprintf (Memc[bkg], SZ_LINE, "%g %g %g %d %d\n")
+ call pargd (z1)
+ call pargd (z2)
+ call pargd (z3)
+ call pargi (i)
+ call pargi (m)
+
+ switch (func) {
+ case 1:
+ xval[j] = z3 * asumr (x[i], m) / m
+ yval[j] = z3 * asumr (y[i], m) / m
+ case 2:
+ xval[j] = z3 * asumr (x[i], m) / m
+ yval[j] = z3 * amedr (y[i], m)
+ }
+ }
+ }
+
+ if (xval[1] == xval[2]) {
+ dy = 0.
+ y1 = (yval[1] + yval[2]) / 2.
+ } else {
+ dy = (yval[2] - yval[1]) / (xval[2] - xval[1])
+ y1 = yval[1] + dy * (x1 - xval[1])
+ }
+ return
+
+err_
+ call sfree (sp)
+ call error (1, "Syntax error in background specification")
+end
+
+
+include <time.h>
+
+# FP_TITLE -- Set title string and print.
+
+procedure fp_title (sh, str, verbose, log)
+
+pointer sh # Spectrum header structure
+char str[SZ_LINE] # Title string
+bool verbose # Verbose?
+int log # Log file descriptor
+
+pointer sp, time, smw
+long clktime()
+
+begin
+ # Select title format.
+ smw = MW(sh)
+ switch (SMW_FORMAT(smw)) {
+ case SMW_ND:
+ call sprintf (str, SZ_LINE, "%s%s: %s")
+ call pargstr (IMNAME(sh))
+ call pargstr (IMSEC(sh))
+ call pargstr (TITLE(sh))
+ case SMW_ES, SMW_MS:
+ call sprintf (str, SZ_LINE, "%s - Ap %d: %s")
+ call pargstr (IMNAME(sh))
+ call pargi (AP(sh))
+ call pargstr (TITLE(sh))
+ }
+
+ # Set time and log header.
+ call smark (sp)
+ call salloc (time, SZ_DATE, TY_CHAR)
+ call cnvdate (clktime(0), Memc[time], SZ_DATE)
+ if (log != NULL) {
+ call fprintf (log, "# %s %s\n")
+ call pargstr (Memc[time])
+ call pargstr (str)
+ }
+ if (verbose) {
+ call printf ("# %s %s\n")
+ call pargstr (Memc[time])
+ call pargstr (str)
+ }
+
+ call sfree (sp)
+end