Blame view

src/idl_extern/CMTotal_for_Dustemwrap/legcheb.pro 4.66 KB
517b8f98   Annie Hughes   first commit
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
;+
; NAME:
;   LEGCHEB
;
; AUTHOR:
;   Craig B. Markwardt, NASA/GSFC Code 662, Greenbelt, MD 20770
;   craigm@lheamail.gsfc.nasa.gov
;   UPDATED VERSIONs can be found on my WEB PAGE: 
;      http://cow.physics.wisc.edu/~craigm/idl/idl.html
;
; PURPOSE:
;   Compute Legendre polynomial coefficents from Chebyshev coefficients
;
; MAJOR TOPICS:
;   Curve and Surface Fitting, Special Functions
;
; CALLING SEQUENCE:
;   b = LEGCHEB(a)
;
; DESCRIPTION:
;
;   This routine computes the coefficients of a Legendre polynomial
;   expansion when the Chebyshev expansion is known.
;
;   Users can determine the Chebyshev expansion coefficients using a
;   routine like CHEBFIT, CHEBCOEF or CHEBGRID.  Then, if the Legendre
;   expansion is needed instead, this conversion routine should be
;   used.  Evaluation of the Legendre series can be performed using
;   the POLYLEG function in the IDL Astronomy Library.
;
;   Internally, the computational precision is double precision.
;   This routine relies upon the algorithm of Piessens (1974).
;
; INPUTS:
;
;   A - a vector, the coefficients of the Chebyshev series of the
;       desired function.
;
; RETURNS:
;
;   The vector B, which contains the coefficients of the Legendre
;   polynomial expansion.  Both A and B will have the same number of
;   elements and data type.
;
; KEYWORD PARAMETERS:
;
;   NONE
;
; EXAMPLE:
;
;   ;; Compute the Chebyshev series coefficients of 1/(2-X) on [-1,1]
;   A = CHEBCOEF('1d/(2d - X)', /expr)
;
;   ;; Convert to Legendre series coefficients
;   B = LEGCHEB(A)
;
; REFERENCES:
;
;   Abramowitz, M. & Stegun, I., 1965, *Handbook of Mathematical
;     Functions*, 1965, U.S. Government Printing Office, Washington,
;     D.C. (Applied Mathematical Series 55)
;   Piessens, R. 1974, Comm. ACM, v. 17, p. 25 (TOMS 473)
;
; MODIFICATION HISTORY:
;   Written and documented, CM, 25 Sep 2002
;
;  $Id: legcheb.pro,v 1.1 2002/09/25 21:12:35 craigm Exp $
;
;-
; Copyright (C) 2002, Craig Markwardt
; This software is provided as is without any warranty whatsoever.
; Permission to use, copy, modify, and distribute modified or
; unmodified copies is granted, provided this copyright and disclaimer
; are included unchanged.
;-

function legcheb, a, reset=reset

  common legcheb_common, ink

  n1 = n_elements(a)
  n  = n1-1

  ;; Internal routine: reset the common block
  if keyword_set(reset) then begin
      ink = 0 & dummy = temporary(ink)
      return, -1d
  endif

  ;; A common block is used to store the matrix which converts from
  ;; one representation to another.  This matrix needs to be expanded
  ;; if the input vector (size N1) is longer than the size of the
  ;; matrix (NINK x NINK).

  nink = sqrt(n_elements(ink))
  if nink LT n1 then begin

      ;; If we've never been called before, initialize the 2x2 array
      ;; with hard coded numbers
      if n_elements(ink) EQ 0 then begin
          ink = reform([[2d,0d],[0d, 2d/3d]], 2,2)
          nink = 2
      endif

      ;; Insert the new array into the old array
      inknew = dblarr(n1,n1)
      inknew(0:nink-1,0:nink-1) = ink
      ink = reform(inknew,n1,n1)
      
      ;; Compute the diagonal components, based on recurrence relation
      ;; in Piessens (1974)
      for nn = nink, n1-1 do begin
          ;; Recurrence relation for diagonal components
          ;; ORIG: ink(nn,nn) = ink(nn-1,nn-1)*4d*nn^2/(2d*nn+1)/(2d*nn)
          ink(nn,nn) = ink(nn-1,nn-1)*2d*nn/(2d*nn+1)
      endfor

      ;; Special case: first row, because of a 0/0 condition
      kk = dindgen(n1/2)*2
      ink(kk,0) = -2d/(kk*kk - 1)
      
      ;; Fill remaining columns of the INK array, using the recurrence
      ;; of eqn 6 in Piessens
      for nn = 1, n1-1 do begin
          ;; KSTART is the starting index, which could be larger than
          ;; NINK because the elements left of the diagonal are always
          ;; zero.  The NINK-1 vs NINK-2 logic is because the cells
          ;; alternate nonzero quantities.
          kstart = nink-1
          if ink(kstart,nn) EQ 0 then kstart = nink-2
          kstart = kstart>nn

          ;; Recurrence used here.
          for kk = kstart, n1-3, 2 do if ink(kk,nn) NE 0 then begin
              ink(kk+2,nn) = (ink(kk,nn) $
                              * (double((kk-1)*kk - nn*(nn+1)) $
                                 / ((kk+3)*(kk+2) - nn*(nn+1))) $
                              * (double(kk+2)/kk))
          end
      endfor
  endif

  ;; Extract relevant portion of INK matrix
  nn = dindgen(n1)
  mat = ink(0:n1-1,0:n1-1)

  ;; Keep same data type for A and B
  b = reform(a)*0.

  ;; Compute B by matrix multiplication
  b(*) = (mat ## a(*))

  ;; Apply final multiplicative factor, the normalization of the
  ;; Legendre polynomials.
  return, b*(0.5d + nn)
end