#include <misc.h>
#include <params.h>
subroutine phcs(pmn ,hmn ,ix ,x1) 1,3
!-----------------------------------------------------------------------
!
! Purpose:
! Compute associated Legendre functions of the first kind of order m and
! degree n, and the associated derivatives for arg x1.
! Method:
! Compute associated Legendre functions of the first kind of order m and
! degree n, and the associated derivatives for arg x1. The associated
! Legendre functions are evaluated using relationships contained in
! "Tables of Normalized Associated Legendre Polynomials",
! S. L. Belousov (1962). Both the functions and their derivatives are
! ordered in a linear stored rectangular array (with a large enough
! domain to contain the particular wavenumber truncation defined in the
! pspect common block) by column. m = 0->ptrm, and n = m->ptrn + m
! m
! The functions P (x) are normalized such that
! n
! / m 2
! | [P (x)] dx = 1/2
! / n
! __
! and must be multiplied by |2 to match Belousov tables.
! \|
! m
! The derivatives H (x) are defined as
! n m 2 m
! H (x) = -(1-x ) dP (x)/dx
! n n
!
! and are evaluated using the recurrence relationship
! _________________________
! m m | 2 2 m
! H (x) = nx P (x) - |(n - m )(2n + 1)/(2n - 1) P (x)
! n n \| n-1
!
! Modified 1/23/97 by Jim Rosinski to use real*16 arithmetic in order to
! achieve (nearly) identical values on all machines.
!
! Author: CCM1
!
!-----------------------------------------------------------------------
!
! $Id: phcs.F90,v 1.1.2.1 2002/06/15 13:46:59 erik Exp $
! $Author: erik $
!
!-----------------------------------------------------------------------
use shr_kind_mod
, only: r8 => shr_kind_r8
use pmgrid
use pspect
implicit none
!------------------------------Arguments--------------------------------
integer , intent(in) :: ix ! Dimension of Legendre funct arrays
real(r8), intent(in) :: x1 ! sin of latitude, [sin(phi), or mu]
real(r8), intent(out) :: pmn(ix) ! Legendre function array
real(r8), intent(out) :: hmn(ix) ! Derivative array
!-----------------------------------------------------------------------
!---------------------------Local variables-----------------------------
#ifdef PGF90
integer, parameter :: r16 = selected_real_kind(12)
#else
integer, parameter :: r16 = selected_real_kind(17)
#endif
integer jmax ! Loop limit (N+1=> 2D wavenumber limit +1)
integer nmax ! Large enough n to envelope truncation
integer n ! 2-D wavenumber index (up/down column)
integer ml ! intermediate scratch variable
integer k ! counter on terms in trig series expansion
integer n2 ! 2*n
integer m ! zonal wavenumber index
integer nto ! intermediate scratch variable
integer mto ! intermediate scratch variable
integer j ! 2-D wavenumber index in recurrence evaluation
integer nmaxm ! loop limit in recurrence evaluation
real(r16) xtemp(3,pmmax+ptrn+1) ! Workspace for evaluating recurrence
! ! relation where xtemp(m-2,n) and
! ! xtemp(m-1,n) contain Pmn's required
! ! to evaluate xtemp(m,n) (i.e.,always
! ! contains three adjacent columns of
! ! the Pmn data structure)
!
real(r16) xx1 ! x1 in extended precision
real(r16) xte ! cosine latitude [cos(phi)]
real(r16) teta ! pi/2 - latitute (colatitude)
real(r16) an ! coefficient on trig. series expansion
real(r16) sinpar ! accumulator in trig. series expansion
real(r16) cospar ! accumulator in trig. series expansion
real(r16) p ! 2-D wavenumber (series expansion)
real(r16) q ! intermediate variable in series expansion
real(r16) r ! zonal wavenumber (recurrence evaluation)
real(r16) p2 ! intermediate variable in series expansion
real(r16) rr ! twice the zonal wavenumber (recurrence)
real(r16) sqp ! intermediate variable in series expansion
real(r16) cosfak ! coef. on cos term in series expansion
real(r16) sinfak ! coef. on sin term in series expansion
real(r16) ateta ! intermediate variable in series expansion
real(r16) costet ! cos term in trigonometric series expansion
real(r16) sintet ! sin term in trigonometric series expansion
!
real(r16) t ! intermediate variable (recurrence evaluation)
real(r16) wm2 ! intermediate variable (recurrence evaluation)
real(r16) wmq2 ! intermediate variable (recurrence evaluation)
real(r16) w ! intermediate variable (recurrence evaluation)
real(r16) wq ! intermediate variable (recurrence evaluation)
real(r16) q2 ! intermediate variable (recurrence evaluation)
real(r16) wt ! intermediate variable (recurrence evaluation)
real(r16) q2d ! intermediate variable (recurrence evaluation)
real(r16) cmn ! cmn recurrence coefficient (see Belousov)
real(r16) xdmn ! dmn recurrence coefficient (see Belousov)
real(r16) emn ! emn recurrence coefficient (see Belousov)
real(r16) n2m1 ! n2 - 1 in extended precision
real(r16) n2m3 ! n2 - 3 in extended precision
real(r16) n2p1nnm1 ! (n2+1)*(n*n-1) in extended precision
real(r16) twopmq ! p + p - q in extended precision
!-----------------------------------------------------------------------
!
! Begin procedure by evaluating the first two columns of the Legendre
! function matrix (i.e., all n for m=0,1) via a trigonometric series
! expansion (see eqs. 19 and 21 in Belousov, 1962). Note that indexing
! is offset by one (e.g., m index for wavenumber m=0 is 1 and so on)
! Setup first ...
!
xx1 = x1
jmax = ptrn + 1
nmax = pmmax + jmax
xte = sqrt(1.-xx1*xx1)
teta = acos(xx1)
an = 1.
xtemp(1,1) = 0.5 ! P00
!
! begin loop over n (2D wavenumber, or degree of associated Legendre
! function) beginning with n=1 (i.e., P00 was assigned above)
! note n odd/even distinction yielding 2 results per n cycle
!
do n=2,nmax
sinpar = 0.
cospar = 0.
ml = n
p = n - 1
p2 = p*p
sqp = 1./sqrt(p2+p)
an = an*sqrt(1. - 1./(4.*p2))
cosfak = 1.
sinfak = p*sqp
do k=1,ml,2
q = k - 1
twopmq = p + p - q
ateta = (p-q)*teta
costet = cos(ateta)
sintet = sin(ateta)
if (n==k) costet = costet*0.5
if (k/=1) then
cosfak = (q-1.)/q*(twopmq+2.)/(twopmq+1.)*cosfak
sinfak = cosfak*(p-q)*sqp
end if
cospar = cospar + costet*cosfak
sinpar = sinpar + sintet*sinfak
end do
xtemp(1,n) = an*cospar ! P0n vector
xtemp(2,n-1) = an*sinpar ! P1n vector
end do
!
! Assign Legendre functions and evaluate derivatives for all n and m=0,1
!
pmn(1) = 0.5
pmn(1+jmax) = xtemp(2,1)
hmn(1) = 0.
hmn(1+jmax) = xx1*xtemp(2,1)
do n=2,jmax
pmn(n) = xtemp(1,n)
pmn(n+jmax) = xtemp(2,n)
n2 = n + n
n2m1 = n2 - 1
n2m3 = n2 - 3
n2p1nnm1 = (n2+1)*(n*n-1)
hmn(n) = (n-1)*(xx1*xtemp(1,n)-sqrt(n2m1/n2m3)*xtemp(1,n-1))
hmn(n+jmax) = n*xx1*xtemp(2,n)-sqrt(n2p1nnm1/n2m1)*xtemp(2,n-1)
end do
!
! Evaluate recurrence relationship for remaining Legendre functions
! (i.e., m=2 ... PTRM) and associated derivatives (see eq 17, Belousov)
!
do m=3,pmmax
r = m - 1
rr = r + r
xtemp(3,1) = sqrt(1.+1./rr)*xte*xtemp(2,1)
nto = (m-1)*jmax
pmn(nto+1) = xtemp(3,1)
hmn(nto+1) = r*xx1*xtemp(3,1)
nmaxm = nmax - m
!
! Loop over 2-D wavenumber (i.e., degree of Legendre function)
! Pmn's and Hmn's for current zonal wavenumber, r
!
do j=2,nmaxm
mto = nto + j
t = j - 1
q = rr + t - 1
wm2 = q + t
w = wm2 + 2
wq = w*q
q2 = q*q - 1
wmq2 = wm2*q2
wt = w*t
q2d = q2 + q2
cmn = sqrt((wq*(q-2.))/(wmq2-q2d))
xdmn = sqrt((wq*(t+1.))/wmq2)
emn = sqrt(wt/((q+1.)*wm2))
xtemp(3,j) = cmn*xtemp(1,j) - xx1*(xdmn*xtemp(1,j+1)-emn*xtemp(3,j-1))
pmn(mto) = xtemp(3,j)
hmn(mto) = (r+t)*xx1*xtemp(3,j) - sqrt(wt*(q+1.)/wm2)*xtemp(3,j-1)
end do
!
! shift Pmn's to left in workspace (setup for next recurrence pass)
!
!++pjr
! not initialized above
xtemp(2,nmax) = 0.
do j=nmaxm,nmax
xtemp(3,j) = 0.
end do
!--pjr
do n=1,nmax
xtemp(1,n) = xtemp(2,n)
xtemp(2,n) = xtemp(3,n)
end do
end do
return
end subroutine phcs