*DECK MOCCHR
      SUBROUTINE MOCCHR(NDIM,NANI,NFUNL,NMU,XMUANG,PHI1,PHI2,R)
*
*-----------------------------------------------------------------------
*
*Purpose:
* Generates all spherical harmonics R(L,M) at point (XMUANG,PHI1).
*
*Copyright:
* Copyright (C) 2002 Ecole Polytechnique de Montreal
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version
*
*Author(s): R. Roy
*
*Parameters: input
* NDIM    number of dimensions for the geometry.
* NANI    scattering anisotropy (=0 for isotropic scattering).
* NFUNL   number of spherical harmonics per polar angle.
* NMU     order of the polar quadrature in 2D / 1 in 3D.
* XMUANG  cosines of the different tracking polar angles.
*         (polar quadrature in 2D / tracking angles in 3D).
* PHI1    first cosine of the tracking azimuthal angle.
* PHI2    second cosine of the tracking azimuthal angle.
*
*Parameters: output
* R       spherical harmonics.
*
*Comments:
*  for 0 <= L <= NANI (and for -L <= M <= L)
*  and for all angles (for 1 <= IMU <= NMU).
*    Definition of spherical harmonics R(L,M):
*    R(L, M)= FACT(L,M)*P(L,M)*COS(M*PHI1)  for 0 < M <= L
*    R(L, 0)=           P(L,0)
*    R(L,-M)= FACT(L,M)*P(L,M)*SIN(M*PHI1)  for 0 < M <= L
*    where FACT(L,M)= SQRT( 2*(L-M)!/(L+M)! )
*
*-----------------------------------------------------------------------
*
      IMPLICIT NONE
*----
*  SUBROUTINE ARGUMENTS
*----
      INTEGER          NDIM,NANI,NFUNL,NMU
      REAL             XMUANG(NMU),R(NMU,NFUNL)
      DOUBLE PRECISION PHI1,PHI2
*----
*  LOCAL VARIABLES
*----
      INTEGER          IMU,L,M,LPM,LMMP1,IND,NSELEC
      LOGICAL          LROK
      DOUBLE PRECISION DPHI,DCOP2,DSIP2,DL00,DL10,DL01,DL11,DM0,DM1,
     >                 DM2,DCOS,DSIN,DCOT,DFAC,DZERO,DONE
      DOUBLE PRECISION, ALLOCATABLE, DIMENSION(:,:) :: RWORK
      PARAMETER ( DZERO= 0.0D0, DONE= 1.0D0 )
*
*     INDEX FOR MATRIX 'RWORK'
      IND(L,M)= L*(L+1) + M + 1
*
***** FIRST, COMPUTES ALL SPHERICAL HARMONICS
*
*     GENERATES ALL LEGENDRE POLYNOMIALS P(L,M) AT POINT XMU
*               FOR 0 <= L <= NANI (AND FOR 0 <= M <= L)
*     USING THE RECURENCE RELATIONS:
*     P(L+1,M)= ((2*L+1)*XMU*P(L,M)-(L+M)*P(L-1,M))/(L-M+1)
*     P(L,M+1)= 2*M*XMU*P(L,M)/SQRT(1-XMU**2)-(L+M)*(L-M+1)*P(L,M-1)
*
*     ESTABLISH SIMPLE CASES
      ALLOCATE(RWORK(NMU,(NANI+1)*(NANI+1)))
      IF( NANI.GE.0 )THEN
         DO 10 IMU= 1, NMU
            RWORK(IMU,IND(0,0))= DONE
   10    CONTINUE
      ELSE
         CALL XABORT('MOCCHR: THE FIRST ARGUMENT MUST NON NEGATIVE')
      ENDIF
*
      IF( NANI.GE.1 )THEN
         DPHI  = SIGN(ACOS(PHI1),PHI2)
         DO 40 IMU= 1, NMU
            DCOS=   DBLE(XMUANG(IMU))
            DSIN=   SQRT( DONE - DCOS  *DCOS   )
            RWORK(IMU,IND(1,-1))= DSIN*PHI2
            RWORK(IMU,IND(1, 0))= DCOS
            RWORK(IMU,IND(1, 1))= DSIN*PHI1
*
            IF( NANI.GE.2 )THEN
*              RECURENCE PLG(IND(L,0)),PLG(IND(L,1) FOR 2 <= L <= NANI
               DCOT= DCOS/DSIN
               DL00= DONE
               DL10= DCOS
               DL01= DZERO
               DL11= DSIN
               DO 30 L= 1, NANI-1
*                 IF M=1, L=L+1 THEN L+M=L+2, L-M+1=L+1
                  LPM=   L + 2
                  LMMP1= L + 1
                  DFAC= (DONE+DONE)/DBLE(LPM*LMMP1)
                  DM0=(DBLE(2*L+1)*DCOS*DL10 - DBLE(L)*DL00)/DBLE(L+1)
                  DM1=(DBLE(2*L+1)*DCOS*DL11 - DBLE(L+1)*DL01)/DBLE(L)
*                 ESTABLISH RELATIONS FOR L=L+1, ABS(M)<=1
                  RWORK(IMU,IND(L+1,-1))= SQRT(DFAC)*DM1*PHI2
                  RWORK(IMU,IND(L+1, 0))= DM0
                  RWORK(IMU,IND(L+1, 1))= SQRT(DFAC)*DM1*PHI1
                  DL00= DL10
                  DL01= DL11
                  DL10= DM0
                  DL11= DM1
*                 RECURENCE PLG(IND(L,M)) FOR 2 <= M <= L
                  DO 20 M= 1, L
*                    HERE DM0=PLG(L+1,0), DM1=PLG(L+1,1)
*                    ESTABLISH RELATIONS FOR L=L+1, ABS(M)>1
                     DFAC= DFAC/DBLE((LMMP1-1)*(LPM+1))
                     DCOP2= COS(DBLE(M+1)*DPHI)
                     DSIP2= SIN(DBLE(M+1)*DPHI)
                     DM2= DBLE(2*M)*DCOT*DM1 - DBLE(LPM*LMMP1)*DM0
                     RWORK(IMU,IND(L+1,-(M+1)))= SQRT(DFAC)*DM2*DSIP2
                     RWORK(IMU,IND(L+1, M+1 ))= SQRT(DFAC)*DM2*DCOP2
                     DM0= DM1
                     DM1= DM2
                     LPM=   LPM   + 1
                     LMMP1= LMMP1 - 1
   20             CONTINUE
   30          CONTINUE
            ENDIF
   40    CONTINUE
      ENDIF
*
***** SELECTS THE GOOD SPHERICAL HARMONICS RWORK(L,M) FUNCTIONS
*             FOR NDIM=1(SLAB),2(TWO-D RECT),3(THREE-D).
*     COMPRESSES RWORK INTO R.
*
      NSELEC= 0
      LROK= .FALSE.
      DO 80 L= 0, NANI
         DO 70 M= -L, L
            IF( NDIM.EQ.1 )THEN
               LROK= M.EQ.0
            ELSEIF( NDIM.EQ.2 )THEN
               LROK= MOD(L+M,2).EQ.0
            ELSEIF( NDIM.EQ.3 )THEN
               LROK= .TRUE.
            ENDIF
            IF( LROK )THEN
               NSELEC= NSELEC+1
               DO 50 IMU= 1, NMU
                  R(IMU,NSELEC)= REAL(RWORK(IMU,IND(L,M)))
   50          CONTINUE
            ENDIF
   70   CONTINUE
   80 CONTINUE
      IF(NSELEC.NE.NFUNL) CALL XABORT('MOCCHR: INVALID NSELEC')
      DEALLOCATE(RWORK)
*
      RETURN
      END
