aboutsummaryrefslogtreecommitdiff
path: root/noao/twodspec/multispec/modgauss5.x
blob: 437b1a859a8c935d7e765981a102e155d4c389e4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
include "ms.h"

# MOD_GAUSS5 -- Set GAUSS5 model profiles and ranges.
#
# This routine can be speeded up with look up tables for a and exp(-z).

define	ZMIN	0		# Issue warning if z < ZMIN
define	ZMAX	10		# The profile values are zero for z > ZMAX

procedure mod_gauss5 (ms, lower, profiles, ranges, len_profile, nspectra)

pointer	ms					# MULTISPEC data structure
real	lower					# Lower limit of profiles
real	profiles[len_profile, nspectra, ARB]	# The profiles to be set
						# The third dim must be >= 5
real	ranges[nspectra, LEN_RANGES]		# The ranges to be set
int	len_profile				# The length of each profile
int	nspectra				# The number of spectra

int	i, j, warn
real	dx, dx2, y, z
real	x1, a, s, s0, s1, s2, s3, profile
real	dIdx0, dIdI0, dIds0, dIds1, dIds2
real	dydx0, dzdx0

begin
	# First set the ranges array.
	call set_ranges (ms, lower, ranges, nspectra)

	# The model quantity x1 is set to 1/4 the profile length.
	# This could someday become a model parameter.
	x1 = len_profile / 4

	# For each spectrum and each point in the profile set the
	# profile/derivative values for the 5 Gauss5 parameters.

	warn = YES
	do i = 1, nspectra {
	    s0 = PARAMETER(ms, S0, i)
	    s1 = PARAMETER(ms, S1, i)
	    s2 = PARAMETER(ms, S2, i)
	    do j = 1, len_profile {
	        dx = ranges[i, DX_START] + j - 1
	        dx2 = dx * dx
	        a = 1 / sqrt (dx2 + x1 ** 2)
	        y = a * dx
		if (y < 0)
		    s3 = s2 - s1
		else
		    s3 = s2 + s1
	        s = s0 + y * s3
	        z = s * dx2
	        if (z < ZMIN) {
		    # Issue warning only once.
		    if (warn == YES) {
		        call printf ("WARNING: mod_gauss5 error.\n")
			warn = NO
		    }
		}
	        if (z < ZMAX) {
		    profile = exp(-z)
		    dydx0 = -(a ** 3) * (x1 ** 2)
		    dzdx0 = -2 * s * dx + dydx0 * s3 * dx2
		    dIdI0 = profile
		    dIdx0 = -dzdx0 * profile
		    dIds0 = -dx2 * profile
		    dIds1 = -dx2 * y * profile
		    dIds2 = dIds1
		    if (y < 0)
			dIds1 = -dIds1

		    profiles[j,i,I0_INDEX] = dIdI0
		    profiles[j,i,X0_INDEX] = dIdx0
		    profiles[j,i,S0_INDEX] = dIds0
		    profiles[j,i,S1_INDEX] = dIds1
		    profiles[j,i,S2_INDEX] = dIds2
		} else {
		    profiles[j,i,I0_INDEX] = 0.
		    profiles[j,i,X0_INDEX] = 0.
		    profiles[j,i,S0_INDEX] = 0.
		    profiles[j,i,S1_INDEX] = 0.
		    profiles[j,i,S2_INDEX] = 0.
		}
	    }
	}
end

# CONSTRAIN_GAUSS5 -- Apply constraints to the solution vector for GAUSS5.
#
# The constraints are:
#
#    DI0 > -I0/2, abs(DX0) < MAX_DX0, DS0 > -S0/2,
#    (S0+DS0)+-(S1+DS1)+(S2+DS2) > 0.
#
# where DI0, DX0, DS0, DS1, DS2 are the solution corrections and I0, S0,
# S1, and S2 are the original parameter values.  The constraints on DI0,
# and DS0 insure that I0 and S0 remain positive and the last constraint
# insures that (S0+-S1+S2) always remains positive so that the profiles
# always decrease from the center.

define	MAX_DX0		1.		# Maximum change in position

procedure constrain_gauss5 (ms, solution, nspectra, nparams)

pointer	ms
real	solution[nspectra, nparams]
int	nspectra
int	nparams

int	i
real	max_delta
real	sa, sb, dsa, dsb, scalea, scaleb, scale

begin
	do i = 1, nspectra {

	    # Limit any decrease in I0 to 1/2 I0.  This insures I0 > 0.
	    if (solution[i, I0_INDEX] != 0.) {
		max_delta = PARAMETER(ms, I0, i) / 2.
		solution[i, I0_INDEX] = max (solution[i, I0_INDEX], -max_delta)
	    }

	    # Limit the correction for X0 to MAX_DX0.
	    # Set the position to INDEF if it falls outside the image.
	    if (solution[i, X0_INDEX] != 0.) {
		max_delta = MAX_DX0
		solution[i, X0_INDEX] = max (solution[i, X0_INDEX], -max_delta)
		solution[i, X0_INDEX] = min (solution[i, X0_INDEX], max_delta)
	    }

	    # Limit any decrease in S0 to 1/2 of S0. This insures S0 > 0.
	    if (solution[i, S0_INDEX] != 0.) {
		max_delta = PARAMETER(ms, S0, i) / 2.
		solution[i, S0_INDEX] = max (solution[i, S0_INDEX], -max_delta)
	    }

	    # Limit the final S0+-S1+S2 to be positive.  If the value would be
	    # negative scale the correction vector (ds0, ds1, ds2) to make
	    # the final S0+-S1+S2 be 1/2 the old value.
	    if ((solution[i,S0_INDEX] != 0.) || (solution[i,S1_INDEX] != 0.) ||
		(solution[i,S2_INDEX] != 0.)) {
		sa = PARAMETER(ms, S0, i) + PARAMETER(ms, S1, i) +
		    PARAMETER(ms, S2, i)
		sb = PARAMETER(ms, S0, i) - PARAMETER(ms, S1, i) +
		    PARAMETER(ms, S2, i)
		dsa = solution[i, S0_INDEX] + solution[i, S1_INDEX] +
		    solution[i, S2_INDEX]
		dsb = solution[i, S0_INDEX] - solution[i, S1_INDEX] +
		    solution[i, S2_INDEX]
		if (sa + dsa < 0.)
		    scalea = -sa / 2 / dsa
		else
		    scalea = 1.
		if (sb + dsb < 0.)
		    scaleb = -sb / 2 / dsb
		else
		    scaleb = 1.
		scale = min (scalea, scaleb)
		solution[i, S0_INDEX] = scale * solution[i, S0_INDEX]
		solution[i, S1_INDEX] = scale * solution[i, S1_INDEX]
		solution[i, S2_INDEX] = scale * solution[i, S2_INDEX]
	    }
	}
end