#define RCSID "$Id: Legendre.c,v 1.15 2006/02/26 00:42:54 geuzaine Exp $"
/*
 * Copyright (C) 1997-2006 P. Dular, C. Geuzaine
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA.
 *
 * Please report all bugs and problems to <getdp@geuz.org>.
 *
 * Contributor(s):
 *   Ruth Sabariego
 */

#include "GetDP.h"
#include "Numeric.h"

double Factorial( double n ){
  /* FACTORIAL(n) is the product of all the integers from 1 to n */  
  double F ;

  GetDP_Begin("Factorial");

  if ( n < 0 ) Msg(GERROR, "Factorial(n): n must be a positive integer") ;
  if ( n == 0 ) GetDP_Return(1.) ;
  if ( n <= 2 ) GetDP_Return(n) ;

  F = n ;
  while ( n > 2 ){ n-- ; F *= n ; }
  
  GetDP_Return(F);
}

double BinomialCoef( double n, double m ){
  /* Binomial Coefficients: (n m) 
     Computes de number of ways of choosing m objects from a collection of n distinct objects */

  int i ;
  double B = 1. ;

  GetDP_Begin("BinomialCoef") ;

  if (m==0 || n==m) GetDP_Return(1.) ;
  for(i = (int)n ; i > m ; i--)
    B *= (double)i/(double)(i-m);

  GetDP_Return(B);
}

double Legendre(int l, int m, double x){

  /* Computes the associated Legendre polynomial P_l^m(x).
     Here the degree l and the order m are the integers
     satisfying -l<=m<=l, while x lies in the range -1<=x<=1 */
     
  double fact, pll=0., pmm,  pmmp1, somx2, Cte ;
  int i, ll;
  
  GetDP_Begin("Legendre");
  
  if ( THEABS(m) > l || fabs(x) > 1.)
    Msg(GERROR, "Bad arguments for Legendre: P_l^m(x) with -l<=m<=l (int), -1<=x<=1 l = %d m = %d x = %.8g", l, m, x);
 
  Cte = (m > 0) ? 1. : Factorial((double)(l-THEABS(m)))/Factorial((double)(l+THEABS(m))) * pow(-1.,(double)THEABS(m)) ;
  m = THEABS(m) ;
  
  pmm = 1. ;
  
  if (m > 0) {
    somx2 =  sqrt((1.-x)*(1.+x)) ;
    fact = 1. ; 
    for (i=1;i<=m;i++){
      pmm *= -fact*somx2 ;
      fact += 2. ;
    }
  }
  if (l==m){
    GetDP_Return( Cte*pmm ) ;
  }
  else {
    pmmp1 = x * (2*m+1)*pmm ;
    if  (l==(m+1)){
      GetDP_Return( Cte*pmmp1 ) ;
    }
    else {
      for (ll=(m+2);ll<=l;ll++) {
	pll = (x*(2*ll-1)*pmmp1-(ll+m-1)*pmm)/(ll-m) ;
	pmm = pmmp1 ;
	pmmp1 = pll ;
      }
      GetDP_Return( Cte*pll ) ;
    }
  }
}

void LegendreRecursive(int l, int m, double x, double P[]){
  /* Computes recursively a (l+1)-terms sequence of the associated Legendre polynomial P_l^m(x).
     l and m are the integers satisfying 0<=m<=l
     x lies in the range -1<=x<=1
     l = maximum order considered, m = invariable */

  int il ;
  double Pl_m, Plm1_m ;


  GetDP_Begin("LegendreRecursive");

  P[0] = Plm1_m = Legendre(0, m, x) ;
  P[1] = Pl_m = Legendre(1, m, x) ;
 
  if (l >=2) 
    for(il = 1 ; il < l ; il ++){    
      P[il+1] = (2*il+1)*x*Pl_m/(il-m+1) + (il+m)*Plm1_m/(m-il-1) ; 
      Plm1_m = Pl_m ;
      Pl_m =  P[il+1];
    }
  else GetDP_End ;

  GetDP_End ;
}

void LegendreRecursiveM(int l, double x, double P[]){
  /* Computes recursively a (l+1)-terms sequence of the associated Legendre polynomial P_l^m(x).
     x lies in the range -1<=x<=1, l = invariable, -l<=m<=l */
  int m ;
  double Pl_m, Plm1_m ;

  GetDP_Begin("LegendreRecursiveM");

  if (fabs(x) == 1.)
    for(m = -l ; m <= l ; m ++) 
      P[l+m] = (m==0) ? pow(THESIGN(x),(double)l) : 0. ;    
  else{
    if (l==0){
      P[0] = Legendre(0, 0, x) ;
      GetDP_End ;
    }
    P[0] = Plm1_m = Legendre(l, -l, x) ;
    P[1] =  Pl_m =  Legendre(l, -l+1, x) ;    
    if (l >= 1)
      for(m = -l+1 ; m < l ; m ++){     
	P[l+m+1] = -2*m*x*Pl_m/sqrt(1-x*x) + (m*(m-1)-l*(l+1))*Plm1_m ; 
	Plm1_m = Pl_m ;
	Pl_m =  P[l+m+1];
      }
    else GetDP_End ;
  }
  
  GetDP_End ;
}

double dLegendre (int l, int m, double x){
  /* Computes the derivative of the associated Legendre polynomial P_l^m(x) */

  double dpl;

  GetDP_Begin("dLegendre");
  
  if ( THEABS(m) > l || fabs(x) > 1.)
    Msg(GERROR,
	"Bad arguments for dLegendre: -l<=m<=l (integers), -1<=x<=1. Current values: l %d m %d x %.8g", l, m, x) ;
  
  if (fabs(x)==1.) dpl = 0.;
  else    
    dpl = ((l+m)*(l-m+1)*sqrt(1-x*x)*((THEABS((m-1))>l) ? 0. :
	  Legendre(l, m-1, x)) + m*x* Legendre (l,m,x))/(1-x*x);
  
  GetDP_Return(dpl);

}

double dLegendreFinDif (int l, int m, double x){
  /* Computes the derivative of the associated Legendre polynomial P_l^m(x)
   using Finite Differences: f'(x) = (f(x+\delta x)-f(x-\delta x))/(2 \delta) */

  double dpl, delta = 1e-6;

  GetDP_Begin("dLegendreFinDif");
  
  if ( THEABS(m) > l || fabs(x) > 1.)
    Msg(GERROR, "Bad arguments for dLegendreFinDif: -l<=m<=l (integers), -1<=x<=1. Current values: l %d m %d x %.8g", l, m, x );
  
  dpl =  (Legendre (l, m, x+delta) - Legendre (l, m, x-delta))/(2*delta);
  
  GetDP_Return(dpl);

}

void PrintLegendre(int l, int m, double x, char * FileName){

  double P ;
  int i ;

  FILE * file ;

  GetDP_Begin("PrintLegendre");

  Msg(INFO, "Writing Legendre: '%s' ", FileName );
  file = fopen(FileName, "w");

  for (i = 1 ; i <= l ; i++ ){
    P = Legendre(i, m, x);
    fprintf(file, "%f \n", P);     
  }

  fclose(file);
  
  GetDP_End;
}

void SphericalHarmonics(int l, int m, double Theta, double Phi, double Yl_m[]){
  
  int am ;
  double cn, Pl_m, F, cRe ;

  GetDP_Begin("SphericalHarmonics");
  
  cn = sqrt((2*l+1)*ONE_OVER_FOUR_PI) ; /* Normalization Factor */
  am = THESIGN(m)*m ; 

  F= sqrt(Factorial((double)(l-am))/ Factorial((double)(l+am))) ;
  Pl_m = Legendre(l, am, cos(Theta));

  cRe = cn * F * Pl_m ;

  Yl_m[0] = cRe*cos(m*Phi) ;
  Yl_m[1] = cRe*sin(m*Phi) ;


  GetDP_End;
}






syntax highlighted by Code2HTML, v. 0.9.1