#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include "header.h"

/** halo pair separation profile for halo with concentration c_NFW
    [satellite-satellite]
    x=r/(2*R_vir)  0<=x<=1
    analytic solution of Sheth et al (2001) MNRAS 325, 1288 (eq.A25)
    dF/dx \propto \lambda(r)*r^2
    normalized so that \int_0^1 dF/dx dx =1
    The normalization factor in this subroutine is obtained from my 
    fitting formula, which has a fractional error less than 0.2% for
    c_NFW in the range ~1 to ~100. The formula is basically a double
    powerlaw with a smooth transition and the residuals are further
    reduced with a (1+sine) function.
 **/
 
double dFdx_ss(double x, double c_NFW)
{
 double f,y,a,Anorm;
 double A0=4.915,alpha=-3.099,beta=0.617,cNFWc=1.651,mu=4.706;
 double B0=0.0336,omega=2.684,phi=0.4079;
 /** above are parameters in fitting formula of the normalization **/
 double t;
 double t1,t2,t3,ta;

 if(x<=0.0 || x>=1.0) return 0.0;

 a=1.0/c_NFW;
 y=2.0*c_NFW*x;


 if(x<0.5)
   {
     f=(-4.0*(1.0+a)+2.0*a*y*(1.0+2.0*a)+a*a*y*y)/(2.0*(1.0+a)*(1.0+a)*(2.0+y));
     f=f+log(fabs((1.0+a-a*y)*(1.0+y))/(1.0+a))/y+y*log(1.0+y)/(2.0+y)/(2.0+y);
   }
 else
   {
     f=y*log((1.0+a)/fabs(a*y+a-1))/(2.0+y)/(2.0+y);
     f=f+0.5*y*(a*a*y-2.0*a)/(1.0+a)/(1.0+a)/(2.0+y);
   }

 /** get the normalization factor from a fitting formula **/
 t=pow(c_NFW/cNFWc,(beta-alpha)/mu);
 Anorm=A0*pow(c_NFW,alpha)*pow(1.0+t,mu)*(1.0+B0*sin(omega*(log10(c_NFW)-phi)));

 return Anorm*f;
}

/** [central-satellite] i.e. the NFW profile rho(r)*r^2
    x=r/(2*R_vir)
 **/

double dFdx_cs(double x, double c_NFW)
{
 double f,A,y;

 if(x>0.5) return 0.0;
 else {
   y=1.0+2.0*c_NFW*x;
   f=x/(y*y);
   A=(log(1.0+c_NFW)-c_NFW/(1.0+c_NFW))/(4.0*c_NFW*c_NFW);
   return f/A;
 }
}

/* The redshift-space one-halo term spends the majority of its time 
 * calculating NFW pair densities for sat-sat pairs. To speed up
 * the calculation, this tabulates the values of dFdx_ss on a grid
 * for bilinear interpolation.
 *
 * In tests, accuracy is usually about 1E-5, and at worst 1E-3.
 */
double dFdx_ss_interp(double r, double c)
{
  static int flag=0,reset=0;
  static double **x;
  static double clo,dlogc,chi;
  int nx=2000, nc=100, i,j,ir,ic;
  double c_nfw,x1,x2,x3,c_fac=2;

  if(!flag)
    {
      x=dmatrix(0,nc,1,nx);
      flag=1;
      if(OUTPUT)
	fprintf(stdout,"dFdx_ss_interp> Tabulating dFdx_ss...\n");
      clo = 0.1;
      chi = 1000.0;
      dlogc = (log(chi)-log(clo))/(nc-1);
      for(j=1;j<=nx;++j)
	x[0][j]=0;
      for(i=1;i<=nc;++i)
	{
	  c_nfw=exp((i-1)*dlogc)*clo;
	  for(j=1;j<=nx;++j) { 
	    x[i][j]=dFdx_ss((double)j/nx,c_nfw); }
	}
      if(OUTPUT)
	fprintf(stdout,"dFdx_ss_interp> ...Finished.\n");
    }
  r*=nx;
  c_fac = log(c/clo)/dlogc+1;
  ir=(int)r;
  ic=(int)c_fac;
  if(ic==0)ic++;
  if(ic==nc)ic--;
  if(ic==0 || ic>=nc) {
    printf("%f %f %f %d\n",r/nx,c,c_fac,ic);
    endrun("dFdx error"); }

  x1=(x[ic][ir+1]-x[ic][ir])*(r-ir)+x[ic][ir];
  x2=(x[ic+1][ir+1]-x[ic+1][ir])*(r-ir)+x[ic+1][ir];
  return((x2-x1)*(c_fac-ic)+x1);
}


/* Well, it looks like it really doesn't help much of anything to tabulate
 * the central-satellite function (which isn't too surprising since the number
 * of computations isn't very large). But the above one seems to do very well.
 */

double dFdx_cs_interp(double r, double c)
{
  static int flag=0;
  static double **x;
  int nx=1000, nc=19, i,j,ir,ic;
  double c_nfw,x1,x2,x3;

  if(r>0.5)return(0);

  if(!flag++)
    {
      fprintf(stderr,"Tabulating dFdx_cs...\n");
      x=dmatrix(0,nc,1,nx);
      for(i=1;i<=nc;++i)
	{
	  c_nfw=i;
	  x[0][j]=0;
	  for(j=1;j<=nx;++j)
	    x[i][j]=dFdx_cs((double)j/nx,c_nfw);
	  fprintf(stderr,"%d\n",i);
	}
      fprintf(stderr,"Finished.\n");
    }
  r*=nx;
  ir=(int)r;
  ic=(int)c;
  if(ic==0 || ic>=nc)
    endrun("dFdx error");

  x1=(x[ic][ir+1]-x[ic][ir])*(r-ir)+x[ic][ir];
  x2=(x[ic+1][ir+1]-x[ic+1][ir])*(r-ir)+x[ic+1][ir];
  return((x2-x1)*(c-ic)+x1);
}
