#include <cstring>
#include <cstdlib>
#include "Elastic.h"
#include <math.h>
#include <stdio.h>
#include <cstdlib>
#include <iostream>
Elastic::Elastic(char* nu_nubar
                ,char* nucCorrectionType
                ,char* fun_GEp
                ,char* fun_GEn
                ,char* fun_GMp 
                ,char* fun_GMn
                ,double mA
                ,double gAcon
                ,double ml
                ,double gPfact
                ,double mV
                ,double accura_int
                ,double gfermi
                ,double coscabibo):
NucCorr(nu_nubar,nucCorrectionType)
{
  strcpy(nu_nub,nu_nubar);
// set number for neutrino or antineutrino
  if(strcmp(nu_nub,"nu")==0)
  {
    i_nu_nubar=-1;
  }
  else if(strcmp(nu_nub,"nub")==0)
  {
    i_nu_nubar= 1;
  }
  else
  {
    cout<<"Neutrino, Antineutrino parameter wrong, nu_nub="<<nu_nub<<endl;
    exit(1);
  }
  strcpy(fun_G_E_p,fun_GEp);
  strcpy(fun_G_E_n,fun_GEn);
  strcpy(fun_G_M_p,fun_GMp);
  strcpy(fun_G_M_n,fun_GMn);
  m_A=mA;
  g_A_con=gAcon;
  m_l=ml;
  g_P_fact=gPfact;
  m_V=mV;
  accurInteg=accura_int;
  Gfermi=gfermi;
  cosCabibo=coscabibo;
//
  strcpy(fun_F_A,"dipole");
//
  strcpy(fun_times_G_E_p,"const");
  fact_G_E_p=1.0;
//
  strcpy(fun_times_G_E_n,"const");
  fact_G_E_n=1.0;
//
  strcpy(fun_times_G_M_p,"const");
  fact_G_M_p=1.0;
//
  strcpy(fun_times_G_M_n,"const");
  fact_G_M_n=1.0;
//
  strcpy(fun_times_F_1_V,"const");
  fact_F_1_V=1.0;
//
  strcpy(fun_times_cF_2_V,"const");
  fact_cF_2_V=1.0;
//
  strcpy(fun_times_F_A,"const");
  fact_F_A=1.0;
}
void  Elastic::InitElastic()
{
  InitNucCorr();
  InitFF_Klink();
}
void  Elastic::InitFF_Tsush_nucl_th_0307013()
{
  set_fun_times_F_1_V("splF1","Tsushima/Tsushima_F1_rat.dat");
  set_fun_times_cF_2_V("splF2","Tsushima/Tsushima_F2_rat.dat");
  set_fun_times_F_A("splFA","Tsushima/Tsushima_GA_rat.dat");
}
void  Elastic::InitFF_Tsush_c12_G()
{
  set_fun_times_G_E_p("splGEp","Tsush/GEMAmed_qmcrat_c12_GEp.dat");
  set_fun_times_G_E_n("splGEn","Tsush/GEMAmed_qmcrat_c12_GEn.dat");
  set_fun_times_G_M_p("splGMp","Tsush/GEMAmed_qmcrat_c12_GMp.dat");
  set_fun_times_G_M_n("splGMn","Tsush/GEMAmed_qmcrat_c12_GMn.dat");
  set_fun_times_F_A("splFA","Tsush/GEMAmed_qmcrat_c12_GA.dat");
}
void  Elastic::InitFF_Tsush_c12_G_to_1_gt_2GeV()
{
  set_fun_times_G_E_p("splGEp","Tsush/GEMAmed_qmcrat_c12_to_1_gt_2GeV_GEp.dat");
  set_fun_times_G_E_n("splGEn","Tsush/GEMAmed_qmcrat_c12_to_1_gt_2GeV_GEn.dat");
  set_fun_times_G_M_p("splGMp","Tsush/GEMAmed_qmcrat_c12_to_1_gt_2GeV_GMp.dat");
  set_fun_times_G_M_n("splGMn","Tsush/GEMAmed_qmcrat_c12_to_1_gt_2GeV_GMn.dat");
  set_fun_times_F_A("splFA","Tsush/GEMAmed_qmcrat_c12_to_1_gt_2GeV_GA.dat");
}
void  Elastic::InitFF_Tsush_fe56_G()
{
  set_fun_times_G_E_p("splGEp","Tsush/GEMAmed_qmcrat_fe56_GEp.dat");
  set_fun_times_G_E_n("splGEn","Tsush/GEMAmed_qmcrat_fe56_GEn.dat");
  set_fun_times_G_M_p("splGMp","Tsush/GEMAmed_qmcrat_fe56_GMp.dat");
  set_fun_times_G_M_n("splGMn","Tsush/GEMAmed_qmcrat_fe56_GMn.dat");
  set_fun_times_F_A("splFA","Tsush/GEMAmed_qmcrat_fe56_GA.dat");
}
void  Elastic::InitFF_Klink()
{
// Initialize spline files of with Klink file.
  set_ff_spline_G_E_p("Klink/gep.d");
  set_ff_spline_G_E_n("Klink/gen.d");
  set_ff_spline_G_M_p("Klink/gmp.d");
  set_ff_spline_G_M_n("Klink/gmn.d");
  set_ff_spline_F_A("Klink/ga.d");
}
double Elastic::dipole(double q2)
{
  double m_V2=m_V*m_V;
  double dip = 1./(1.0-q2/m_V2);
  return dip*dip;
}
double Elastic::Olsson(double q2)
{
  double Q=sqrt(-q2);
  double q2cut=-5.8;
  double Qcut=sqrt(-q2cut);
  if(-q2<5.8)
  {
    return dipole(q2)*sqrt((1.0-(0.053+0.017*Q)*sin(4.00*Q/(1.0+0.22*Q)) ));
  }
  else
  {
    return 0.4/(q2*q2)-0.4/(q2cut*q2cut)
          +dipole(q2cut)*sqrt((1.0-(0.053+0.017*Qcut)*sin(4.00*Qcut/(1.0+0.22*Qcut)) ));
  }
}
double Elastic::tau(double q2)
{
  return -q2/(4.0*M2);
}
double Elastic::G_E_V(double q2)
{
  return G_E_p(q2)-G_E_n(q2);
}
double Elastic::G_M_V(double q2)
{
  return G_M_p(q2)-G_M_n(q2);
}
double Elastic::G_E_p(double q2)
{
  return Factor_times_G_E_p(q2)*G_E_p_nucleon(q2);
}
double Elastic::Factor_times_G_E_p(double q2)
{
  double Q2=-q2;
  if(strcmp(fun_times_G_E_p,"const")==0)
  {
    return fact_G_E_p; 
  }
  else if(strcmp(fun_times_G_E_p,"splGEp")==0)
  {
    return splineFile_G_E_p.Splint(Q2); 
  }
  else
  {
    cout<<" bad intentifier for Factor_times_G_E_p ="<<fun_times_G_E_p<<endl;
    exit(1);
  }    
}
double Elastic::G_E_p_nucleon(double q2)
{
  if(strcmp(fun_G_E_p,"dipole")==0)
  {
    return G_E_p_dipole(q2);
  }    
  else if(strcmp(fun_G_E_p,"JRA_CS")==0)
  {
    return G_E_p_JRA_CS(q2);
  }    
  else if(strcmp(fun_G_E_p,"JRA_CS_7")==0)
  {
    return G_E_p_JRA_CS_7(q2);
  }    
  else if(strcmp(fun_G_E_p,"JRA_CS_8")==0)
  {
    return G_E_p_JRA_CS_8(q2);
  }    
  else if(strcmp(fun_G_E_p,"JRA_CS_3_03")==0)
  {
    return G_E_p_JRA_CS_3_03(q2);
  }    
  else if(strcmp(fun_G_E_p,"JRA_CS_q")==0)
  {
    return G_E_p_JRA_CS_q(q2);
  }    
  else if(strcmp(fun_G_E_p,"JRA_CS_HallA")==0)
  {
    return G_E_p_JRA_CS_HallA(q2);
  }    
  else if(strcmp(fun_G_E_p,"JRA_CS_HallA_7")==0)
  {
    return G_E_p_JRA_CS_HallA_7(q2);
  }    
  else if(strcmp(fun_G_E_p,"JRA_CS_HallA_8")==0)
  {
    return G_E_p_JRA_CS_HallA_8(q2);
  }    
  else if(strcmp(fun_G_E_p,"JRA_CS_HallA_3_03")==0)
  {
    return G_E_p_JRA_CS_HallA_3_03(q2);
  }    
  else if(strcmp(fun_G_E_p,"JRA_CS_HallA_q")==0)
  {
    return G_E_p_JRA_CS_HallA_q(q2);
  }    
  else if(strcmp(fun_G_E_p,"Olsson")==0)
  {
    return G_E_p_Olsson(q2);
  }
  else if(strcmp(fun_G_E_p,"zero")==0)
  {
    return 0.0;
  }    
  else if(strcmp(fun_G_E_p,"spline")==0)
  {
    return  G_E_p_spline(q2);
  }    
  else if(strcmp(fun_G_E_p,"AB")==0)
  {
    return  G_E_p_AB(q2);
  }    
  else if(strcmp(fun_G_E_p,"Kelly")==0)
  {
    return  G_E_p_Kelly(q2);
  }    
  else
  {
    cout<<" bad intentifier for G_E_p"<<endl;
    exit(1);
  }    
}
double Elastic::G_E_p_dipole(double q2)
{
  return dipole(q2);
}
double Elastic::G_E_p_Olsson(double q2)
{
  return Olsson(q2); 
}
double Elastic::G_E_p_JRA_CS(double q2)
{
// CROSS SECTION DATA ONLY, JRA May 03 fit:
  const int num_para=6;
  double pcoef[num_para] =
  {3.226,1.508,-0.3773,0.6109,-0.1853,0.01596};// GEp CS(6)
  double denom=1.0;
  if(q2>=q2_GEp_GMp)
  {
    for(int iPow=0;iPow<num_para;iPow++)
    {
      denom+=pcoef[iPow]*pow(-q2,iPow+1);
    }
    return 1.0/denom;
  }
  else
  {
    return G_M_p_JRA_CS(q2)*G_E_p_JRA_CS(q2_GEp_GMp)/
        G_M_p_JRA_CS(q2_GEp_GMp);
  }
}
double Elastic::G_E_p_JRA_CS_7(double q2)
{
// CROSS SECTION DATA ONLY, JRA May 03 fit:
  const int num_para=7;
  double pcoef[num_para] =
  {3.217,1.484,-0.3293,0.6651,-0.2426,0.03014,-0.001048};// GEp CS(7)
  double denom=1.0;
  for(int iPow=0;iPow<num_para;iPow++)
  {
    denom+=pcoef[iPow]*pow(-q2,iPow+1);
  }
  return 1.0/denom;
}
double Elastic::G_E_p_JRA_CS_8(double q2)
{
// CROSS SECTION DATA ONLY, JRA May 03 fit:
  const int num_para=8;
  double pcoef[num_para] =
  {3.259,0.8015,1.738,-1.759,1.130,-0.3669,0.05515,-0.003070};// GEp CS(8)
  double denom=1.0;
  for(int iPow=0;iPow<num_para;iPow++)
  {
    denom+=pcoef[iPow]*pow(-q2,iPow+1);
  }
  return 1.0/denom;
}
double Elastic::G_E_p_JRA_CS_3_03(double q2)
{
// CROSS SECTION DATA ONLY:
  const int num_para=4;
  double pcoef[num_para] = {3.41018, 0.89084,0.52979,-0.01736};
  double denom=1.0;
  for(int iPow=0;iPow<num_para;iPow++)
  {
    denom+=pcoef[iPow]*pow(-q2,iPow+1);
  }
  return 1.0/denom;
}
double Elastic::G_E_p_JRA_CS_q(double q2)
{
// CROSS SECTION DATA ONLY:
  const int num_para=6;
  double Q=sqrt(-q2);
  double pcoef[num_para] = {-0.04441, 4.12640, -3.66197, 5.68686, -1.23696, 0.08346};
  double denom=1.0;
  for(int iPow=0;iPow<num_para;iPow++)
  {
    denom+=pcoef[iPow]*pow(Q,iPow+1);
  }
  return 1.0/denom;
}
double Elastic::G_E_p_JRA_CS_HallA(double q2)
{
//CROSS SECTION AND POLARIZATION DATA, JRA May 03 fit:
  const int num_para=6;
  double pcoef[num_para] =
  {3.253,1.422,0.08582,0.3318,-0.09371,0.01076};// GEp CS(6) HallA
  double denom=1.0;
  if(q2>=q2_GEp_GMp)
  {
    for(int iPow=0;iPow<num_para;iPow++)
    {
      denom+=pcoef[iPow]*pow(-q2,iPow+1);
    }
    return 1.0/denom;
  }
  else
  {
    return G_M_p_JRA_CS_HallA(q2)*G_E_p_JRA_CS_HallA(q2_GEp_GMp)/
        G_M_p_JRA_CS_HallA(q2_GEp_GMp);

  }
}
double Elastic::G_E_p_JRA_CS_HallA_7(double q2)
{
//CROSS SECTION AND POLARIZATION DATA, JRA May 03 fit:
  const int num_para=7;
  double pcoef[num_para] =
  {3.264,1.100,0.9530,-0.5084,0.3045,-0.07987,0.007699};// GEp CS(7) HallA
  double denom=1.0;
  for(int iPow=0;iPow<num_para;iPow++)
  {
    denom+=pcoef[iPow]*pow(-q2,iPow+1);
  }
  return 1.0/denom;
}
double Elastic::G_E_p_JRA_CS_HallA_8(double q2)
{
//CROSS SECTION AND POLARIZATION DATA:
  const int num_para=8;
  double pcoef[num_para] =
  {3.262,0.8560,1.677,-1.290,0.7573,-0.2302,0.03312,-0.001639};// GEp CS(8) HallA
  double denom=1.0;
  for(int iPow=0;iPow<num_para;iPow++)
  {
    denom+=pcoef[iPow]*pow(-q2,iPow+1);
  }
  return 1.0/denom;
}
double Elastic::G_E_p_JRA_CS_HallA_3_03(double q2)
{
//CROSS SECTION AND POLARIZATION DATA:
  const int num_para=4;
  double pcoef[num_para] = {3.31713,1.27721,0.39593,0.07636};
  double denom=1.0;
  for(int iPow=0;iPow<num_para;iPow++)
  {
    denom+=pcoef[iPow]*pow(-q2,iPow+1);
  }
  return 1.0/denom;
}
double Elastic::G_E_p_JRA_CS_HallA_q(double q2)
{
//CROSS SECTION AND POLARIZATION DATA:
  const int num_para=6;
  double Q=sqrt(-q2);
  double pcoef[num_para] = {-0.21867, 5.89885, -9.96209, 16.23405, -9.63712, 2.90093};
  double denom=1.0;
  for(int iPow=0;iPow<num_para;iPow++)
  {
    denom+=pcoef[iPow]*pow(Q,iPow+1);
  }
  return 1.0/denom;
}
double Elastic::G_E_p_spline(double q2)
{
// note the spline file has + Q2
   double gep=G_E_p_Spline.Splint(-q2);
// if outside the spline fit use dipole
   if(gep==0)
   {
     double q2_max=-G_E_p_Spline.Return_xMaxSpline();
     gep=G_E_p_Spline.Splint(-q2_max)*G_E_p_dipole(q2)/G_E_p_dipole(q2_max);
   }
   return gep;
}
double Elastic::G_E_p_AB(double q2)
{
// Bodek Bradford fit
  const int num_para_a=1;
  double acoef[num_para_a]={-.05777087};
  double numerator=1.0;
  double tau_q2=tau(q2);
  for(int iPow=0;iPow<num_para_a;iPow++)
  {
    numerator+=acoef[iPow]*pow(tau_q2,iPow+1);
  }
  const int num_para_b=3;
  double bcoef[num_para_b]={11.17884,13.64415,33.0309};
  double denom=1.0;
  for(int iPow=0;iPow<num_para_b;iPow++)
  {
    denom+=bcoef[iPow]*pow(tau_q2,iPow+1);
  }
  return numerator/denom;
}
double Elastic::G_E_p_Kelly(double q2)
{
// Kelly fit PRC 70 068202, (2004) 
  const int num_para_a=1;
  double acoef[num_para_a]={-0.24};
  double numerator=1.0;
  double tau_q2=tau(q2);
  for(int iPow=0;iPow<num_para_a;iPow++)
  {
    numerator+=acoef[iPow]*pow(tau_q2,iPow+1);
  }
  const int num_para_b=3;
  double bcoef[num_para_b]={10.98,12.82,21.97};
  double denom=1.0;
  for(int iPow=0;iPow<num_para_b;iPow++)
  {
    denom+=bcoef[iPow]*pow(tau_q2,iPow+1);
  }
  return numerator/denom;
}
// G_E_n
double Elastic::G_E_n(double q2)
{
  return Factor_times_G_E_n(q2)*G_E_n_nucleon(q2);
}
double Elastic::Factor_times_G_E_n(double q2)
{
  double Q2=-q2;
  if(strcmp(fun_times_G_E_n,"const")==0)
  {
    return fact_G_E_n; 
  }
  else if(strcmp(fun_times_G_E_n,"splGEn")==0)
  {
    return splineFile_G_E_n.Splint(Q2); 
  }
  else
  {
    cout<<" bad intentifier for Factor_times_G_E_n ="<<fun_times_G_E_n<<endl;
    exit(1);
  }    
}
double Elastic::G_E_n_nucleon(double q2)
{
  if(strcmp(fun_G_E_n,"zero")==0)
  {
    return G_E_n_zero(q2);
  }
  else if(strcmp(fun_G_E_n,"Krutov")==0)
  {
    return G_E_n_Krutov(q2);
  }
  else if(strcmp(fun_G_E_n,"Galster")==0)
  {
    return G_E_n_Galster(q2);
  }
  else if(strcmp(fun_G_E_n,"JRA")==0)
  {
    return G_E_n_JRA(q2);
  }    
  else if(strcmp(fun_G_E_n,"spline")==0)
  {
    return  G_E_n_spline(q2);
  }    
  else if(strcmp(fun_G_E_n,"AB")==0)
  {
    return  G_E_n_AB(q2);
  }    
  else if(strcmp(fun_G_E_n,"Kelly")==0)
  {
    return  G_E_n_Kelly(q2);
  }    
  else
  {
    cout<<" bad intentifier for G_E_n"<<endl;
    exit(1);
  }    
}
double Elastic::G_E_n_zero(double q2)
{
  return 0;
}
double Elastic::G_E_n_Krutov(double q2)
{
  double a_n_E= 0.942; // new 0.942, 0 is nominal
  double b_n_E=4.61;
  return -mu_n*a_n_E*tau(q2)*dipole(q2)/(1.0+b_n_E*tau(q2));
}
double Elastic::G_E_n_Galster(double q2)
{
  double a_n_E= 1.0;
  double b_n_E=5.6;
  return -mu_n*a_n_E*tau(q2)*dipole(q2)/(1.0+b_n_E*tau(q2));
}
double Elastic::G_E_n_Kelly(double q2)
{
// Kelly fit PRC 70 068202, (2004) 
  double a_n_E= 1.7;
  double b_n_E=3.3;
  return a_n_E*tau(q2)*dipole(q2)/(1.0+b_n_E*tau(q2));
}
double Elastic::G_E_n_JRA(double q2)
{ 
  double a_n_E_JRA = 0.574;
  double b_n_E_JRA = 16.37;
  return -mu_n*a_n_E_JRA*tau(q2)*dipole(q2)/(1.0+b_n_E_JRA*tau(q2));
}
double Elastic::G_E_n_spline(double q2)
{
// note the spline file has + Q2
   double ff=G_E_n_Spline.Splint(-q2);
// if outside the spline fit use dipole
   if(ff==0)
   {
     double q2_max=-G_E_n_Spline.Return_xMaxSpline();
     ff=G_E_n_Spline.Splint(-q2_max)*dipole(q2)/dipole(q2_max);
   }
   return ff;
}
double Elastic::G_E_n_AB(double q2)
{
// Bodek Bradford fit
  const int num_para_a=2;
  double acoef[num_para_a]={1.249971,1.297130};
  double numerator=0.0;
  double tau_q2=tau(q2);
  for(int iPow=0;iPow<num_para_a;iPow++)
  {
    numerator+=acoef[iPow]*pow(tau_q2,iPow+1);
  }
  const int num_para_b=4;
  double bcoef[num_para_b]={-9.861796,305.5084,-758.3796,801.7726};
  double denom=1.0;
  for(int iPow=0;iPow<num_para_b;iPow++)
  {
    denom+=bcoef[iPow]*pow(tau_q2,iPow+1);
  }
  return numerator/denom;
}
// G_M_p
double Elastic::G_M_p(double q2)
{
  return Factor_times_G_M_p(q2)*G_M_p_nucleon(q2);
}
double Elastic::Factor_times_G_M_p(double q2)
{
  double Q2=-q2;
  if(strcmp(fun_times_G_M_p,"const")==0)
  {
    return fact_G_M_p; 
  }
  else if(strcmp(fun_times_G_M_p,"splGMp")==0)
  {
    return splineFile_G_M_p.Splint(Q2); 
  }
  else
  {
    cout<<" bad intentifier for Factor_times_G_M_p ="<<fun_times_G_M_p<<endl;
    exit(1);
  }    
}
double Elastic::G_M_p_nucleon(double q2)
{
  if(strcmp(fun_G_M_p, "dipole")==0)
  {
    return G_M_p_dipole(q2);
  }    
  else if(strcmp(fun_G_M_p, "JRA_CS")==0)
  {
    return G_M_p_JRA_CS(q2);
  }    
  else if(strcmp(fun_G_M_p, "JRA_CS_7")==0)
  {
    return G_M_p_JRA_CS_7(q2);
  }    
  else if(strcmp(fun_G_M_p, "JRA_CS_8")==0)
  {
    return G_M_p_JRA_CS_8(q2);
  }    
  else if(strcmp(fun_G_M_p, "JRA_CS_3_03")==0)
  {
    return G_M_p_JRA_CS_3_03(q2);
  }    
  else if(strcmp(fun_G_M_p, "JRA_CS_q")==0)
  {
    return G_M_p_JRA_CS_q(q2);
  }    
  else if(strcmp(fun_G_M_p, "JRA_CS_HallA")==0)
  {
    return G_M_p_JRA_CS_HallA(q2); 
  }    
  else if(strcmp(fun_G_M_p, "JRA_CS_HallA_7")==0)
  {
    return G_M_p_JRA_CS_HallA_7(q2); 
  }    
  else if(strcmp(fun_G_M_p, "JRA_CS_HallA_8")==0)
  {
    return G_M_p_JRA_CS_HallA_8(q2); 
  }    
  else if(strcmp(fun_G_M_p, "JRA_CS_HallA_3_03")==0)
  {
    return G_M_p_JRA_CS_HallA_3_03(q2); 
  }    
  else if(strcmp(fun_G_M_p, "JRA_CS_HallA_q")==0)
  {
    return G_M_p_JRA_CS_HallA_q(q2); 
  }    
  else if(strcmp(fun_G_M_p, "Olsson")==0)
  {
    return G_M_p_Olsson(q2);
  }   
  else if(strcmp(fun_G_M_p, "zero")==0)
  {
    return 0.0;
  }   
  else if(strcmp(fun_G_M_p,"spline")==0)
  {
    return  G_M_p_spline(q2);
  }    
  else if(strcmp(fun_G_M_p,"AB")==0)
  {
    return  G_M_p_AB(q2);
  }    
  else if(strcmp(fun_G_M_p,"Kelly")==0)
  {
    return  G_M_p_Kelly(q2);
  }    
  else
  {
    cout<<" bad intentifier for G_M_p"<<endl;
    exit(1);
  }    
}
double Elastic::G_M_p_dipole(double q2)
{
  return (1.0+mu_p)*dipole(q2);
}
double Elastic::G_M_p_JRA_CS(double q2)
{
//CROSS SECTION DATA ONLY, JRA May 03 fit:
  const int num_para=6;
  double pcoef[num_para] =
  {3.188,1.354,0.1511,-0.01135,0.0005330,-0.9005E-05};// GMp CS(6)
  double denom=1.0;
  for(int iPow=0;iPow<num_para;iPow++)
  {
    denom+=pcoef[iPow]*pow(-q2,iPow+1);
  }
  return (1.0+mu_p)/denom;
}
double Elastic::G_M_p_JRA_CS_7(double q2)
{
// CROSS SECTION DATA ONLY, JRA May 03 fit:
  const int num_para=7;
  double pcoef[num_para] =
  {3.227,1.264,0.2067,-0.02406,0.001754,-0.00005846,0.6980E-06};// GMp CS(7)
  double denom=1.0;
  for(int iPow=0;iPow<num_para;iPow++)
  {
    denom+=pcoef[iPow]*pow(-q2,iPow+1);
  }
  return (1.0+mu_p)/denom;
}
double Elastic::G_M_p_JRA_CS_8(double q2)
{
// CROSS SECTION DATA ONLY, JRA May 03 fit:
  const int num_para=8;
  double pcoef[num_para] =
  {3.259,1.176,0.2712,-0.04357,0.004460,-0.0002395,0.6350E-05,-0.6589E-07};// GMp CS(8)
  double denom=1.0;
  for(int iPow=0;iPow<num_para;iPow++)
  {
    denom+=pcoef[iPow]*pow(-q2,iPow+1);
  }
  return (1.0+mu_p)/denom;
}
double Elastic::G_M_p_JRA_CS_3_03(double q2)
{
// CROSS SECTION DATA ONLY:
  const int num_para=4;
  double pcoef[num_para] = {3.11023, 1.51696, 0.07519, -0.00096};
  double denom=1.0;
  for(int iPow=0;iPow<num_para;iPow++)
  {
    denom+=pcoef[iPow]*pow(-q2,iPow+1);
  }
  return (1.0+mu_p)/denom;
}
double Elastic::G_M_p_JRA_CS_q(double q2)
{
// CROSS SECTION DATA ONLY:
  const int num_para=6;
  double Q=sqrt(-q2);
  double pcoef[num_para] = {-0.53916 ,6.88174 ,-7.59353 ,7.63581 ,-2.11479 ,0.33256};
  double denom=1.0;
  for(int iPow=0;iPow<num_para;iPow++)
  {
    denom+=pcoef[iPow]*pow(Q,iPow+1);
  }
  return (1.0+mu_p)/denom;
}
double Elastic::G_M_p_JRA_CS_HallA(double q2)
{
//CROSS SECTION AND POLARIZATION DATA, JRA May 03 fit:
  const int num_para=6;
  double pcoef[num_para] =
  {3.104,1.428,0.1112,-0.006981,0.0003705,-0.7063E-05};// GMp CS(6) HallA
  double denom=1.0;
  if(q2>=q2_FF_dipole) // the denom goes to zero for q2=-40.8243
  {
    for(int iPow=0;iPow<num_para;iPow++)
    {
      denom+=pcoef[iPow]*pow(-q2,iPow+1);
    }
    return (1.0+mu_p)/denom;
  }
  else
  {
    for(int iPow=0;iPow<num_para;iPow++)
    {
      denom+=pcoef[iPow]*pow(-q2_FF_dipole,iPow+1);
    }
    return G_M_p_dipole(q2)*(1.0+mu_p)/(denom*G_M_p_dipole(q2_FF_dipole));
  }
}
double Elastic::G_M_p_JRA_CS_HallA_7(double q2)
{
//CROSS SECTION AND POLARIZATION DATA, JRA May 03 fit:
  const int num_para=7;
  double pcoef[num_para] =
  {3.165,1.296,0.1903,-0.02554,0.002228,-0.00008500,0.1130E-05};// GMp CS(7) HallA
  double denom=1.0;
  for(int iPow=0;iPow<num_para;iPow++)
  {
    denom+=pcoef[iPow]*pow(-q2,iPow+1);
  }
  return (1.0+mu_p)/denom;
}
double Elastic::G_M_p_JRA_CS_HallA_8(double q2)
{
//CROSS SECTION AND POLARIZATION DATA, JRA May 03 fit:
  const int num_para=8;
  double pcoef[num_para] =
  {3.246,1.106,0.3278,-0.06722,0.008159,-0.0004942,0.00001427,-0.1568E-06};// GMp CS(8) HallA
  double denom=1.0;
  for(int iPow=0;iPow<num_para;iPow++)
  {
    denom+=pcoef[iPow]*pow(-q2,iPow+1);
  }
  return (1.0+mu_p)/denom;
}
double Elastic::G_M_p_JRA_CS_HallA_3_03(double q2)
{
//CROSS SECTION AND POLARIZATION DATA:
  const int num_para=4;
  double pcoef[num_para] = {3.08005, 1.48656, 0.08001, -0.00114};
  double denom=1.0;
  for(int iPow=0;iPow<num_para;iPow++)
  {
    denom+=pcoef[iPow]*pow(-q2,iPow+1);
  }
  return (1.0+mu_p)/denom;
}
double Elastic::G_M_p_JRA_CS_HallA_q(double q2)
{
//CROSS SECTION AND POLARIZATION DATA:
  const int num_para=6;
  double Q=sqrt(-q2);
  double pcoef[num_para] = {-0.43584, 6.18608, -6.25097, 6.52819, -1.75359, 0.28736};
  double denom=1.0;
  for(int iPow=0;iPow<num_para;iPow++)
  {
    denom+=pcoef[iPow]*pow(Q,iPow+1);
  }
  return (1.0+mu_p)/denom; 
}
double Elastic::G_M_p_Olsson(double q2)
{
  return (1.0+mu_p)*Olsson(q2);
}
double Elastic::G_M_p_spline(double q2)
{
// note the spline file has + Q2
   double ff=G_M_p_Spline.Splint(-q2);
// if outside the spline fit use dipole
   if(ff==0)
   {
     double q2_max=-G_M_p_Spline.Return_xMaxSpline();
     ff=G_M_p_Spline.Splint(-q2_max)*G_M_p_dipole(q2)/G_M_p_dipole(q2_max);
   }
   return ff;
}
double Elastic::G_M_p_AB(double q2)
{
// Bodek Bradford fit
  const int num_para_a=1;
  double acoef[num_para_a]={0.1502468};
  double numerator=1.0;
  double tau_q2=tau(q2);
  for(int iPow=0;iPow<num_para_a;iPow++)
  {
    numerator+=acoef[iPow]*pow(tau_q2,iPow+1);
  }
  const int num_para_b=3;
  double bcoef[num_para_b]={11.05393,19.60770,7.544214};
  double denom=1.0;
  for(int iPow=0;iPow<num_para_b;iPow++)
  {
    denom+=bcoef[iPow]*pow(tau_q2,iPow+1);
  }
  return (1.0+mu_p)*numerator/denom;
}
double Elastic::G_M_p_Kelly(double q2)
{
// Kelly fit PRC 70 068202, (2004) 
  const int num_para_a=1;
  double acoef[num_para_a]={0.12};
  double numerator=1.0;
  double tau_q2=tau(q2);
  for(int iPow=0;iPow<num_para_a;iPow++)
  {
    numerator+=acoef[iPow]*pow(tau_q2,iPow+1);
  }
  const int num_para_b=3;
  double bcoef[num_para_b]={10.97,18.86,6.55};
  double denom=1.0;
  for(int iPow=0;iPow<num_para_b;iPow++)
  {
    denom+=bcoef[iPow]*pow(tau_q2,iPow+1);
  }
  return (1.0+mu_p)*numerator/denom;
}
// G_M_n
double Elastic::G_M_n(double q2)
{
  return Factor_times_G_M_n(q2)*G_M_n_nucleon(q2);
}
double Elastic::Factor_times_G_M_n(double q2)
{
  double Q2=-q2;
  if(strcmp(fun_times_G_M_n,"const")==0)
  {
    return fact_G_M_n; 
  }
  else if(strcmp(fun_times_G_M_n,"splGMn")==0)
  {
    return splineFile_G_M_n.Splint(Q2); 
  }
  else
  {
    cout<<" bad intentifier for Factor_times_G_M_n ="<<fun_times_G_M_n<<endl;
    exit(1);
  }    
}
double Elastic::G_M_n_nucleon(double q2)
{
  if(strcmp(fun_G_M_n,"dipole")==0)
  {
    return G_M_n_dipole(q2);
  }    
  else if(strcmp(fun_G_M_n,"JRA")==0)
  {
    return G_M_n_JRA(q2);
  }    
  else if(strcmp(fun_G_M_n,"JRA_q")==0)
  {
    return G_M_n_JRA_q(q2);
  }    
  else if(strcmp(fun_G_M_n,"Kubon")==0)
  {
    return G_M_n_Kubon(q2);
  }    
  else if(strcmp(fun_G_M_n,"Olsson")==0)
  {
    return G_M_n_Olsson(q2);
  }
  else if(strcmp(fun_G_M_n,"spline")==0)
  {
    return  G_M_n_spline(q2);
  }    
  else if(strcmp(fun_G_M_n,"AB")==0)
  {
    return  G_M_n_AB(q2);
  }    
  else if(strcmp(fun_G_M_n,"Kelly")==0)
  {
    return  G_M_n_Kelly(q2);
  }    
  else
  {
    cout<<" bad intentifier for G_M_n"<<endl;
    exit(1);
  }    
}
double Elastic::G_M_n_dipole(double q2)
{
  return mu_n*dipole(q2);
}
double Elastic::G_M_n_JRA(double q2)
{
// Tue, 13 May 2003 fits the fits that were done
// GMp(2) chisq_nu= 2.440
// GMp(3) chisq_nu= 2.132
// GMp(4) chisq_nu= 2.144
// GMp(5) chisq_nu= 2.128 the fit which is here
// GMp(6) chisq_nu= 2.147
// GMp(7) chisq_nu= 2.168
// 
  const int num_para=5;
  double pcoef[num_para] = {3.043,0.8548,0.6806,-0.1287,0.008912};
  double denom=1.0;
  for(int iPow=0;iPow<num_para;iPow++)
  {
    denom+=pcoef[iPow]*pow(-q2,iPow+1);
  }
  return mu_n/denom;
}
double Elastic::G_M_n_JRA_q(double q2)
{
  const int num_para=4;
  double Q=sqrt(-q2);
  double pcoef[num_para] = {-0.40468,5.6569,-4.6645,3.8811};
  double denom=1.0;
  for(int iPow=0;iPow<num_para;iPow++)
  {
    denom+=pcoef[iPow]*pow(Q,iPow+1);
  }
  return mu_n/denom;
}
double Elastic::G_M_n_Kubon(double q2)
{
  const int num_para=5;
  double Q2=-q2;
  double bcoef[num_para] = {3.26, -0.272, 0.0123, -2.52, 2.55};
  double tmp3=Q2*bcoef[3]/(1.0+Q2*bcoef[4]);
  double tmp2=Q2*bcoef[2]/(1.0+tmp3);
  double tmp1=Q2*bcoef[1]/(1.0+tmp2);
  double tmp0=Q2*bcoef[0]/(1.0+tmp1);
  double Gmn=mu_n/(1.0+tmp0);
//  cout<<" tmp= "<<tmp3<<" "<<tmp2<<" "<<tmp1<<" "<<tmp0<<" "<<endl;
//  cout<< "In Kubon, Gmn="<<Gmn<<endl;
  return Gmn;
}
double Elastic::G_M_n_Olsson(double q2)
{
  return mu_n*Olsson(q2);
}
double Elastic::G_M_n_spline(double q2)
{
// note the spline file has + Q2
   double ff=G_M_n_Spline.Splint(-q2);
// if outside the spline fit use dipole
   if(ff==0)
   {
     double q2_max=-G_M_n_Spline.Return_xMaxSpline();
     ff=G_M_n_Spline.Splint(-q2_max)*G_M_n_dipole(q2)/G_M_n_dipole(q2_max);
   }
   return ff;
}
double Elastic::G_M_n_AB(double q2) {
// Bodek Bradford fit
  const int num_para_a=1;
  double acoef[num_para_a]={1.817919};
  double numerator=1.0;
  double tau_q2=tau(q2);
  for(int iPow=0;iPow<num_para_a;iPow++)
  {
    numerator+=acoef[iPow]*pow(tau_q2,iPow+1);
  }
  const int num_para_b=3;
  double bcoef[num_para_b]={14.09648,20.70172,68.66369};
  double denom=1.0;
  for(int iPow=0;iPow<num_para_b;iPow++)
  {
    denom+=bcoef[iPow]*pow(tau_q2,iPow+1);
  }
  return mu_n*numerator/denom;
}
double Elastic::G_M_n_Kelly(double q2)
{
// Kelly fit PRC 70 068202, (2004) 
  const int num_para_a=1;
  double acoef[num_para_a]={2.33};
  double numerator=1.0;
  double tau_q2=tau(q2);
  for(int iPow=0;iPow<num_para_a;iPow++)
  {
    numerator+=acoef[iPow]*pow(tau_q2,iPow+1);
  }
  const int num_para_b=3;
  double bcoef[num_para_b]={14.72,24.20,84.1};
  double denom=1.0;
  for(int iPow=0;iPow<num_para_b;iPow++)
  {
    denom+=bcoef[iPow]*pow(tau_q2,iPow+1);
  }
  return mu_n*numerator/denom;
}
double Elastic::F_1_V(double q2)
{
  return Factor_times_F_1_V(q2)
         *(1./(1.-q2/(4.0*M2)))*(G_E_V(q2)-(q2/(4.0*M2))*G_M_V(q2));
}
double Elastic::Factor_times_F_1_V(double q2)
{
  double Q2=-q2;
  if(strcmp(fun_times_F_1_V,"const")==0)
  {
    return fact_F_1_V; 
  }
  else if(strcmp(fun_times_F_1_V,"splF1")==0)
  {
    return splineFile_F_1_V.Splint(Q2); 
  }
  else
  {
    cout<<" bad intentifier for Factor_times_F_1_V ="<<fun_times_F_1_V<<endl;
    exit(1);
  }    
}
double Elastic::cF_2_V(double q2)
{
  return Factor_times_cF_2_V(q2)
         *(1./(1.-q2/(4.0*M2)))*(G_M_V(q2)-G_E_V(q2));
}
double Elastic::Factor_times_cF_2_V(double q2)
{
  double Q2=-q2;
  if(strcmp(fun_times_cF_2_V,"const")==0)
  {
    return fact_cF_2_V; 
  }
  else if(strcmp(fun_times_cF_2_V,"splF2")==0)
  {
    return splineFile_cF_2_V.Splint(Q2); 
  }
  else
  {
    cout<<" bad intentifier for Factor_times_cF_2_V = "<<fun_times_cF_2_V<<endl;
    exit(1);
  }    
}
double Elastic::F_A(double q2)
{
  return Factor_times_F_A(q2)*F_A_nucleon(q2);
}
double Elastic::F_A_nucleon(double q2)
{
// done'nt know what F_A is to put in several guesses
  double Q2=-q2;
  if(strcmp(fun_F_A,"dipole")==0)
  {
    return F_A_dipole(q2);
  }    
  else if(strcmp(fun_F_A,"G_E_p_JRA_CS")==0)
  {
    return F_A_dipole(q2)*G_E_p_JRA_CS(q2)/G_E_p_dipole(q2);
  }    
  else if(strcmp(fun_F_A,"G_E_p_JRA_CS_HallA")==0)
  {
    return F_A_dipole(q2)*G_E_p_JRA_CS_HallA(q2)/G_E_p_dipole(q2);
  }    
  else if(strcmp(fun_F_A,"F1_V_eq_A")==0)
  {
    return F_A_F1_V_eq_A(q2);
  }    
  else if(strcmp(fun_F_A,"F2_V_eq_A")==0)
  {
    return F_A_F2_V_eq_A(q2);
  }    
  if(strcmp(fun_F_A,"zero")==0)
  {
    return 0.0;
  }    
  else if(strcmp(fun_F_A,"spline")==0)
  {
    return  F_A_spline(q2);
  }
  else
  {
    cout<<" bad intentifier for F_A_nucleon = "<<fun_F_A<<endl;
    exit(1);
  }    
}    
double Elastic::Factor_times_F_A(double q2)
{
  double Q2=-q2;
  if(strcmp(fun_times_F_A,"const")==0)
  {
    return fact_F_A; 
  }
  else if(strcmp(fun_times_F_A,"splFA")==0)
  {
    return splineFile_F_A.Splint(Q2); 
  }
  else
  {
    cout<<" bad intentifier for Factor_times_F_A = "<<fun_times_F_A<<endl;
    exit(1);
  }    
}
double Elastic::F_A_dipole(double q2)
{
  double mA2=m_A*m_A;
  return g_A_con/pow(1.0-q2/mA2,2);
}
double Elastic::F_A_F1_V_eq_A(double q2)
// for q2 make axial = vector 
{
  double gmv= G_M_p_nucleon(q2)-G_M_n_nucleon(q2);
  double fa_v=sqrt(tau(q2)/(1.+tau(q2)))*gmv;
  double fa_dipole=F_A_dipole(q2);
  if(fa_v<-fa_dipole&&q2>-2.0) // so we only use the F_A dipole near zero
  {
     return fa_dipole;
  }
  else
  {
     return -fa_v;
  }
} 
double Elastic::F_A_F2_V_eq_A(double q2)
// for q2 make axial = vector 
{
  double gev= G_E_p_nucleon(q2)-G_E_n_nucleon(q2);
  double gmv= G_M_p_nucleon(q2)-G_M_n_nucleon(q2);
  double fa_v=sqrt((gev*gev+tau(q2)*gmv*gmv)/(1.+tau(q2)));
  double fa_dipole=F_A_dipole(q2);
  if(fa_v<-fa_dipole&&q2>-2.0) // so we only use the F_A dipole near zero
  {
     return fa_dipole;
  }
  else
  {
     return -fa_v;
  }
} 
double Elastic::F_A_spline(double q2)
{
// note the spline file has + Q2
   double ff=F_A_Spline.Splint(-q2);
// if outside the spline fit use dipole
   if(ff==0)
   {
     double q2_max=-F_A_Spline.Return_xMaxSpline();
     ff=F_A_Spline.Splint(-q2_max)*F_A_dipole(q2)/F_A_dipole(q2_max);
   }
   return ff;
}
double Elastic::F_P(double q2)
{
  return g_P_fact*2.0*M2*F_A(q2)/(m_pi*m_pi-q2);
}
double Elastic::coef_F_A_2(double q2, double e_nu)
// coef for F_A**2
{
  if(e_nu<=e_min())
  {
    return very_small;
  }
  else if(q2>q2_min(e_nu)||q2<q2_max(e_nu))
  {
    return very_small;
  }
  else
  {
    double M4 = M2*M2;
    double coef= Nuke(q2,e_nu)*QE_coef(e_nu); 
    double s_u = S_U(q2,e_nu);
    double m_l2 = m_l*m_l;
    return coef*( (m_l*m_l-q2)*(4-q2/M2-m_l2/M2)/(4.0*M2)+0.25*s_u*s_u/M4) ;
  }
}
double Elastic::coef_F_A_1(double q2, double e_nu)
// coef for F_A
{
  if(e_nu<=e_min())
  {
    return very_small;
  }
  else if(q2>q2_min(e_nu)||q2<q2_max(e_nu))
  {
    return very_small;
  }
  else
  {
    double m_l2 = m_l*m_l;
    double coef= Nuke(q2,e_nu)*QE_coef(e_nu); 
    return coef*( -i_nu_nubar*S_U(q2,e_nu)*(q2/M2)*(F_1_V(q2)+cF_2_V(q2))/M2
                - (m_l*m_l-q2)*(m_l2/M2)*4*F_P(q2)/(4.0*M2) );
  }
}
double Elastic::coef_F_A_0(double q2, double e_nu)
{
  if(e_nu<=e_min())
  {
    return very_small;
  }
  else if(q2>q2_min(e_nu)||q2<q2_max(e_nu))
  {
    return very_small;
  }
  else
  {
    double M4 = M2*M2;
    double coef=Nuke(q2,e_nu)*QE_coef(e_nu);
    double s_u = S_U(q2,e_nu);
    double m_l2 = m_l*m_l;
    double small_term=
           -(m_l2/M2)*( (F_1_V(q2)+cF_2_V(q2))*(F_1_V(q2)+cF_2_V(q2))
                      + (2.*F_P(q2))*(2.*F_P(q2))
                      + (q2/M2-4.0)*F_P(q2)*F_P(q2) ) ;
    double A = ((m_l*m_l-q2)/(4.0*M2))
       *(  -(4+q2/M2)*F_1_V(q2)*F_1_V(q2)
           -(q2/M2)*cF_2_V(q2)*cF_2_V(q2)*(1+q2/(4.0*M2))
           -4.0*q2*F_1_V(q2)*cF_2_V(q2)/M2
           +small_term );
    double C =  0.25*(F_1_V(q2)*F_1_V(q2)-(q2/M2)*cF_2_V(q2)*cF_2_V(q2)/4.0);
    return coef*(A + C*s_u*s_u/M4);
  }
}
double Elastic::A(double q2)
{
  double m_l2 = m_l*m_l;
  double small_term=
         -(m_l2/M2)*( (F_1_V(q2)+cF_2_V(q2))*(F_1_V(q2)+cF_2_V(q2))
                    + (F_A(q2)+2.*F_P(q2))*(F_A(q2)+2.*F_P(q2))
                    + (q2/M2-4.0)*F_P(q2)*F_P(q2) ) ;
  return ((m_l*m_l-q2)/(4.0*M2))
     *(   (4-q2/M2)*F_A(q2)*F_A(q2)
         -(4+q2/M2)*F_1_V(q2)*F_1_V(q2)
         -(q2/M2)*cF_2_V(q2)*cF_2_V(q2)*(1+q2/(4.0*M2))
         -4.0*q2*F_1_V(q2)*cF_2_V(q2)/M2
         +small_term );
}
double Elastic::Awrite(double q2)
{
  double m_l2 = m_l*m_l;
  double a1=(4-q2/M2)*F_A(q2)*F_A(q2);
  double a2=-(4+q2/M2)*F_1_V(q2)*F_1_V(q2);
  double a3=-(q2/M2)*cF_2_V(q2)*cF_2_V(q2)*(1+q2/(4.0*M2));
  double a4=-4.0*q2*F_1_V(q2)*cF_2_V(q2)/M2;
  double asum=a1+a2+a3+a4;
  double A=asum*(m_l*m_l-q2)/(4.0*M2);
  cout<<" a1= "<<a1<<" a2= "<<a2<<" a3= "<<a3<<" a4= "<<a4<<endl; 
  cout<<"asum = "<<asum<<" A = "<<A<<endl;
  return ((m_l*m_l-q2)/(4.0*M2))
     *(   (4-q2/M2)*F_A(q2)*F_A(q2)
         -(4+q2/M2)*F_1_V(q2)*F_1_V(q2)
         -(q2/M2)*cF_2_V(q2)*cF_2_V(q2)*(1+q2/(4.0*M2))
         -4.0*q2*F_1_V(q2)*cF_2_V(q2)/M2
         -(m_l2/M2)*( (F_1_V(q2)+cF_2_V(q2))*(F_1_V(q2)+cF_2_V(q2))
                    + (F_A(q2)+2.*F_P(q2))*(F_A(q2)+2.*F_P(q2))
                    + (q2/M2-4.0)*F_P(q2)*F_P(q2) ) );
}
double Elastic::A_q2zero()
{
  double m_l2 = m_l*m_l;
  double m_pi2=m_pi*m_pi;
  double term1=(1.0+mu_p-mu_n)*(1.0+mu_p-mu_n);
  return (m_l2/(4.0*M2))
       *(4.0*g_A_con*g_A_con - 4.0 
       - (m_l2/M2)*(term1+g_A_con*g_A_con*(1.0+8.0*M2/m_pi2)));
}
double Elastic::B(double q2)
{
  return  -(q2/M2)*F_A(q2)*(F_1_V(q2)+cF_2_V(q2));
}
double Elastic::C(double q2)
{
  return 0.25*(F_A(q2)*F_A(q2)+F_1_V(q2)*F_1_V(q2)-(q2/M2)*cF_2_V(q2)*cF_2_V(q2)/4.0);
}
double Elastic::QE_coef(double e_nu ) 
{
  return M2*Gfermi*Gfermi*pow(cosCabibo,2)*hbarc2/(8*pi*e_nu*e_nu);
}
double Elastic::S_U(double q2, double e_nu ) 
{
  return 4.0*m_P*e_nu + q2-m_l*m_l;
}
double Elastic::dsigma_dq2(double q2, double e_nu ) 
{
  if(e_nu<=e_min())
  {
    return very_small;
  }
  else if(q2>q2_min(e_nu)||q2<q2_max(e_nu))
  {
    return very_small;
  }
  else
  {
    double M4 = M2*M2;
    double s_u = S_U(q2,e_nu);
//    double s_u = 4.0*m_P*e_nu + q2-m_l*m_l;
//  cout<< " coef = "<< coef <<" s_u = "<<s_u<<endl;
//  cout<< " coef = "<< coef <<" cont/(e_nu*e_nu) = "<< cont/(e_nu*e_nu) <<endl;
    return Nuke(q2,e_nu)*QE_coef(e_nu)*(A(q2) + i_nu_nubar*s_u*B(q2)/M2 + C(q2)*s_u*s_u/M4);
  }
}
double Elastic::q2_min(double e_nu)
{
  return q_squared(e_nu,m_P,m_P,1.0);
}
double Elastic::q2_max(double e_nu)
{
  return q_squared(e_nu,m_P,m_P,-1.0);
}
double Elastic::e_min()
{
  return m_l + m_l*m_l/(2.0*m_P);
}
double Elastic::e_lep(double q2, double e_nu)
{
// energy of the charged lepton
  return e_nu +q2/(2.0*m_P);
}
double Elastic::cos_theta(double q2, double e_nu)
{
// angle between the neutrino direction and the lepton direction
  return 1.0 + q2/(2.0*e_nu*e_lep(q2,e_nu));
}
//double Elastic::q_3(double q2, double e_nu)
//{
//  space component of q
//  double p_l=sqrt(e_lep(q2,e_nu)*e_lep(q2,e_nu)-m_l*m_l);
//  double sin_theta = sqrt(1-cos_theta(q2,e_nu)*cos_theta(q2,e_nu));
//  return sqrt(e_nu*e_nu+p_l*p_l-2.0*e_nu*p_l*sin_theta);
//}
double Elastic::q_squared(double e_nu,double M_1,double M_2,double cos_theta)
{
  if(e_nu<=e_min())
  {
    return very_small;
  }
  else
  {
// M_1 is the target nucleon, M_2 is the recoil nucleon.
    double s=(2*e_nu*m_P+m_P*m_P);
    double e_nu_cm=(s-M_1*M_1)/(2.0*sqrt(s));
    double e_lep_cm=(s+m_l*m_l-M_2*M_2)/(2.0*sqrt(s));
    double p_nu_cm=e_nu_cm;
    double p_lep_cm=(sqrt(s)/2)*sqrt((1-(m_l+M_2)*(m_l+M_2)/s)*(1-(m_l-M_2)*(m_l-M_2)/s));
    double q_squa=m_l*m_l-2*(e_nu_cm*e_lep_cm-p_nu_cm*p_lep_cm*cos_theta);
//  cout<<"s = "<<s<<" e_nu_cm = "<<e_nu_cm<<" e_lep_cm = "<<e_lep_cm<<endl;
//  cout<< " p_nu_cm = "<<p_nu_cm<<" p_lep_cm = "<<p_lep_cm<<endl;
//  cout<<" q_squa = "<< q_squa<<endl;
    return q_squa<0 ? q_squa : 0.0;
  }
}
double Elastic::sigma_fixed_step(double e_nu )
{
  if(e_nu<=e_min())
  {
    return very_small;
  }
  else
  {
//  remember q2 is negative
    int nstep=20000;
//    int nstep=20000;
    double step=(q2_min(e_nu)-q2_max(e_nu))/nstep;
    double sig=0;
    for(int istep=0;istep<nstep;istep++)
    {
      double xstep=istep;
      double q2=q2_min(e_nu)-(0.5+xstep)*step;
      sig+=dsigma_dq2(q2, e_nu )*step;
//    cout<<" istep = "<<istep<<", -q2 = "<<q2
//    <<", dsigma_dq2 = "<<dsigma_dq2(-q2, e_nu )
//    <<", sigma = "<<sig<<endl;
    }
    return sig;
  }
}
double Elastic::FuncToInteg(char* stg,double xval,double cPara[nSize_cPara])
{
  if(strcmp(stg,"dsigma_dq2")==0)
  {
    return dsigma_dq2(xval,*cPara);
  }
  else
  {
    cout<<" Wrong name for function to integrate,stg="<<stg<<endl;
    exit(1);
  }
}
double Elastic::sigma(double e_nu)
// use Integrate.C to do integration
{
  if(e_nu<=e_min())
  {
    return very_small;
  }
  else
  {
    double q2min=q2_min(e_nu);
    double q2max=q2_max(e_nu);
    return Integr("dsigma_dq2",&e_nu,q2max,q2min,accurInteg);
  }
}
// return the values of the constructor
char* Elastic::ret_nu_nub() {return nu_nub;}
char* Elastic::ret_fun_G_E_p() {return fun_G_E_p;}
char* Elastic::ret_fun_G_E_n() {return fun_G_E_n;}
char* Elastic::ret_fun_G_M_p() {return fun_G_M_p;}
char* Elastic::ret_fun_G_M_n() {return fun_G_M_n;}
char* Elastic::ret_fun_F_A()  {return fun_F_A;}
double Elastic::ret_m_A()     {return m_A;}
double Elastic::ret_g_A_con() {return g_A_con;}
double Elastic::ret_m_l() {return m_l;}
double Elastic::ret_g_P_fact() {return g_P_fact;}
double Elastic::ret_m_V()     {return m_V;}
double Elastic::ret_fact_G_E_p()  {return fact_G_E_p;}
double Elastic::ret_fact_G_E_n()  {return fact_G_E_n;}
double Elastic::ret_fact_G_M_p()  {return fact_G_M_p;}
double Elastic::ret_fact_G_M_n()  {return fact_G_M_n;}
double Elastic::ret_fact_F_A()  {return fact_F_A;}
double Elastic::ret_fact_F_1_V()  {return fact_F_1_V;}
double Elastic::ret_fact_cF_2_V()  {return fact_cF_2_V;}
char* Elastic::ret_fun_times_G_E_p()  {return fun_times_G_E_p;}
char* Elastic::ret_fun_times_G_E_n()  {return fun_times_G_E_n;}
char* Elastic::ret_fun_times_G_M_p()  {return fun_times_G_M_p;}
char* Elastic::ret_fun_times_G_M_n()  {return fun_times_G_M_n;}
char* Elastic::ret_fun_times_F_A()  {return fun_times_F_A;}
char* Elastic::ret_fun_times_F_1_V()  {return fun_times_F_1_V;}
char* Elastic::ret_fun_times_cF_2_V()  {return fun_times_cF_2_V;}

//set the value private values of the object
//void Elastic::set_nucCorrType(char* nucCorTyp) {strcpy(nucCorrType,nucCorTyp);}
//void Elastic::set_fun_G_E_p(char* fun_GEp) {strcpy(fun_G_E_p,fun_GEp);}
//void Elastic::set_fun_G_E_n(char* fun_GEn) {strcpy(fun_G_E_n,fun_GEn);}
//void Elastic::set_fun_G_M_p(char* fun_GMp) {strcpy(fun_G_M_p,fun_GMp);}
//void Elastic::set_fun_G_M_n(char* fun_GMn) {strcpy(fun_G_M_n,fun_GMn);}
//void Elastic::set_g_A_con(double gAcon) { g_A_con=gAcon;}
//void Elastic::set_m_l(double  ml) { m_l=ml;}
//void Elastic::set_g_P_fact(double  gPfact) { g_P_fact=gPfact;}
void Elastic::set_m_A(double  mA) {m_A = mA;}
void Elastic::set_accurInteg(double  accur_int) {accurInteg=accur_int;}
void Elastic::set_fact_G_E_p(double factr_G_E_p) { fact_G_E_p= factr_G_E_p;}
void Elastic::set_fact_G_E_n(double factr_G_E_n) { fact_G_E_n= factr_G_E_n;}
void Elastic::set_fact_G_M_p(double factr_G_M_p) { fact_G_M_p= factr_G_M_p;}
void Elastic::set_fact_G_M_n(double factr_G_M_n) { fact_G_M_n= factr_G_M_n;}
void Elastic::set_fact_F_A(double factr_F_A) { fact_F_A= factr_F_A;}
void Elastic::set_fact_F_1_V(double factr_F_1_V) { fact_F_1_V= factr_F_1_V;}
void Elastic::set_fact_cF_2_V(double factr_cF_2_V) { fact_cF_2_V= factr_cF_2_V;}
void Elastic::set_ff_spline_G_E_p(char* file_for_spline) 
{
// fun_mult_G_E_p chooses the function 
  G_E_p_Spline.Set_spline_file(file_for_spline);
  G_E_p_Spline.MakeSplineObjFromFile();
}
void Elastic::set_ff_spline_G_E_n(char* file_for_spline) 
{
// fun_mult_G_E_n chooses the function 
  G_E_n_Spline.Set_spline_file(file_for_spline);
  G_E_n_Spline.MakeSplineObjFromFile();
}
void Elastic::set_ff_spline_G_M_p(char* file_for_spline) 
{
// fun_mult_G_M_p chooses the function 
  G_M_p_Spline.Set_spline_file(file_for_spline);
  G_M_p_Spline.MakeSplineObjFromFile();
}
void Elastic::set_ff_spline_G_M_n(char* file_for_spline) 
{
// fun_mult_G_M_n chooses the function 
  G_M_n_Spline.Set_spline_file(file_for_spline);
  G_M_n_Spline.MakeSplineObjFromFile();
}
void Elastic::set_ff_spline_F_A(char* file_for_spline) 
{
// fun_mult_F_A chooses the function 
  F_A_Spline.Set_spline_file(file_for_spline);
  F_A_Spline.MakeSplineObjFromFile();
}


void Elastic::set_fun_times_G_E_p(char* fun_mult_G_E_p,char* file_for_spline) 
{
// fun_mult_G_E_p chooses the function 
  strcpy(fun_times_G_E_p,fun_mult_G_E_p);
  splineFile_G_E_p.Set_spline_file(file_for_spline);
  splineFile_G_E_p.MakeSplineObjFromFile();
}
void Elastic::set_fun_times_G_E_n(char* fun_mult_G_E_n,char* file_for_spline) 
{
// fun_mult_G_E_n chooses the function 
  strcpy(fun_times_G_E_n,fun_mult_G_E_n);
  splineFile_G_E_n.Set_spline_file(file_for_spline);
  splineFile_G_E_n.MakeSplineObjFromFile();
}
void Elastic::set_fun_times_G_M_p(char* fun_mult_G_M_p,char* file_for_spline) 
{
// fun_mult_G_M_p chooses the function 
  strcpy(fun_times_G_M_p,fun_mult_G_M_p);
  splineFile_G_M_p.Set_spline_file(file_for_spline);
  splineFile_G_M_p.MakeSplineObjFromFile();
}
void Elastic::set_fun_times_G_M_n(char* fun_mult_G_M_n,char* file_for_spline) 
{
// fun_mult_G_M_n chooses the function 
  strcpy(fun_times_G_M_n,fun_mult_G_M_n);
  splineFile_G_M_n.Set_spline_file(file_for_spline);
  splineFile_G_M_n.MakeSplineObjFromFile();
}
void Elastic::set_fun_times_F_A(char* fun_mult_F_A,char* file_for_spline) 
{
// fun_mult_F_A chooses the function 
  strcpy(fun_times_F_A,fun_mult_F_A);
  splineFile_F_A.Set_spline_file(file_for_spline);
  splineFile_F_A.MakeSplineObjFromFile();
}
void Elastic::set_fun_times_F_1_V(char* fun_mult_F_1_V,char* file_for_spline) 
{
// fun_mult_F_1_V chooses the function 
  strcpy(fun_times_F_1_V,fun_mult_F_1_V);
  splineFile_F_1_V.Set_spline_file(file_for_spline);
  splineFile_F_1_V.MakeSplineObjFromFile();
}
void Elastic::set_fun_times_cF_2_V(char* fun_mult_cF_2_V,char* file_for_spline) 
{
// fun_mult_cF_2_V chooses the function 
  strcpy(fun_times_cF_2_V,fun_mult_cF_2_V);
  splineFile_cF_2_V.Set_spline_file(file_for_spline);
  splineFile_cF_2_V.MakeSplineObjFromFile();
}
void Elastic::set_fun_F_A(char* fun_choice_F_A) 
{
// fun_choice_F_A chooses the function, 
// Its not really a multi factor, like fun_mult_F_1_V is for F_1_V. 
  strcpy(fun_F_A,fun_choice_F_A);
}
//
void Elastic::set_fun_F_A(char* fun_choice_F_A,char* file_for_spline ) 
{
// fun_choice_F_A chooses the function, 
// Its not really a multi factor, like fun_mult_F_1_V is for F_1_V. 
  strcpy(fun_F_A,fun_choice_F_A);
  splineFile_F_A.Set_spline_file(file_for_spline);
  splineFile_F_A.MakeSplineObjFromFile();
}
//
void Elastic::WriteElastic()
{
  cout<<" ( nu_nub="<<nu_nub<<", m_A=" <<m_A<<", g_A=" <<g_A_con<<", m_V="<<m_V<<endl;
  cout<<" ( GEp="<<ret_fun_G_E_p()<<", GEn="<<ret_fun_G_E_n()
      <<", GMp="<<ret_fun_G_M_p() <<", GMn="<<ret_fun_G_M_n()
      <<",  F_A = "<<ret_fun_F_A()<<endl;
  WriteNucCorr();  
//
  if(strcmp(fun_times_G_E_p,"const")==0)
  {
    cout<<" ( fun_times_G_E_p = "<<ret_fun_times_G_E_p()
	<<", fact_G_E_p = "<<ret_fact_G_E_p()<<endl;
  }
  else
  {
    cout<<" ( fun_times_G_E_p = "<<ret_fun_times_G_E_p() 
        <<", Spline File  = "<< splineFile_G_E_p.Ret_spline_file()<<endl;
  }
//
  if(strcmp(fun_times_G_E_n,"const")==0)
  {
    cout<<" ( fun_times_G_E_n = "<<ret_fun_times_G_E_n()
	<<", fact_G_E_n = "<<ret_fact_G_E_n()<<endl;
  }
  else
  {
    cout<<" ( fun_times_G_E_n = "<<ret_fun_times_G_E_n() 
        <<", Spline File  = "<< splineFile_G_E_n.Ret_spline_file()<<endl;
  }
//
  if(strcmp(fun_times_G_M_p,"const")==0)
  {
    cout<<" ( fun_times_G_M_p = "<<ret_fun_times_G_M_p()
	<<", fact_G_M_p = "<<ret_fact_G_M_p()<<endl;
  }
  else
  {
    cout<<" ( fun_times_G_M_p = "<<ret_fun_times_G_M_p() 
        <<", Spline File  = "<< splineFile_G_M_p.Ret_spline_file()<<endl;
  }
//
  if(strcmp(fun_times_G_M_n,"const")==0)
  {
    cout<<" ( fun_times_G_M_n = "<<ret_fun_times_G_M_n()
	<<", fact_G_M_n = "<<ret_fact_G_M_n()<<endl;
  }
  else
  {
    cout<<" ( fun_times_G_M_n = "<<ret_fun_times_G_M_n() 
        <<", Spline File  = "<< splineFile_G_M_n.Ret_spline_file()<<endl;
  }
//
  if(strcmp(fun_times_F_A,"const")==0)
  {
    cout<<" ( fun_times_F_A = "<<ret_fun_times_F_A()
	<<", fact_F_A = "<<ret_fact_F_A()<<endl;
  }
  else
  {
    cout<<" ( fun_times_F_A = "<<ret_fun_times_F_A() 
        <<", Spline File  = "<< splineFile_F_A.Ret_spline_file()<<endl;
  }
//
  if(strcmp(fun_times_F_1_V,"const")==0)
  {
    cout<<" ( fun_times_F_1_V = "<<ret_fun_times_F_1_V()
	<<", fact_F_1_V = "<<ret_fact_F_1_V()<<endl;
  }
  else
  {
    cout<<" ( fun_times_F_1_V = "<<ret_fun_times_F_1_V() 
        <<", Spline File  = "<< splineFile_F_1_V.Ret_spline_file()<<endl;
  }
//
  if(strcmp(fun_times_cF_2_V,"const")==0)
  {
    cout<<" ( fun_times_cF_2_V = "<<ret_fun_times_cF_2_V()
        <<", fact_F_1_V = "<<ret_fact_F_1_V()<<endl;
  }
  else
  {
    cout<<" ( fun_times_cF_2_V = "<<ret_fun_times_cF_2_V() 
	<<", Spline File = "<< splineFile_cF_2_V.Ret_spline_file()<<endl;
  }
//
  if(strcmp(fun_times_F_A,"const")==0)
  {
    cout<<" ( fun_times_F_A = "<<ret_fun_times_F_A()
        <<", fact_F_1_V = "<<ret_fact_F_1_V()<<endl;
  }
  else
  {
    cout<<" ( fun_times_F_A = "<<ret_fun_times_F_A() 
	<<", Spline File = "<< splineFile_F_A.Ret_spline_file()<<endl;
  }
}
