#include "machdefs.h" #include #include #include #include #include #include #include "pexceptions.h" #include "histos.h" #include "hisprof.h" #include "srandgen.h" #include "geneutils.h" namespace SOPHYA { //------------------------------------------------------------------- // Classe d'interpolation lineaire: // Le vecteur y a n elements y_i tels que y_i = f(x_i) // ou les x_i sont regulierement espaces // et x_0=xmin et x_{n-1}=xmax (xmax inclus!) InterpFunc::InterpFunc(double xmin,double xmax,vector& y) : _xmin(xmin), _xmax(xmax), _y(y) { if(_xmin>=_xmax || _y.size()<=2) { // au moins 3 points! cout<<"InterpFunc::InterpFunc : bad arguments values"<_xmax) ok=2; x -= _xmin; long i = long(x/_dx); // On prend le "i" juste en dessous if(i<0) i=0; else if(i>=_nm1) i=_nm1-1; return _y[i] + (_y[i+1]-_y[i])/_dx*(x-i*_dx); } double InterpFunc::Parab(double x,unsigned short& ok) { ok=0; if(x<_xmin) ok=1; else if(x>_xmax) ok=2; x -= _xmin; long i = long(x/_dx+0.5); // On prend le "i" le + proche if(i<1) i=1; else if(i>=_nm1-1) i=_nm1-2; double a = (_y[i+1]-2.*_y[i]+_y[i-1])/(2.*_dx*_dx); double b = (_y[i+1]-_y[i-1])/(2.*_dx); return _y[i] + (x-i*_dx)*(a*(x-i*_dx)+b); } //------------------------------------------------------------------- // Classe d'inversion d'une fonction STRICTEMENT MONOTONE CROISSANTE // // - On part de deux vecteurs x,y de "Nin" elements tels que "y_i = f[x_i]" // ou la fonction "f" est strictement monotone croissante: // x(i) < x(i+1) et y(i) < y(i+1) // - Le but de la classe est de remplir un vecteur X de "Nout" elements // tels que: X_j = f^-1[Y_j] avec j=[0,Nout[ // avec les Y_j regulierement espaces entre ymin=y(0) , ymax=y(Nin -1) // cad: X_j = f^-1[ ymin+j*(ymax-ymin)/(Nout-1) ] // - La construction du vecteur X est realisee // par interpolation lineaire (ComputeLinear) ou parabolique (ComputeParab) InverseFunc::InverseFunc(vector& x,vector& y) : _ymin(0.) , _ymax(0.) , _x(x) , _y(y) { uint_4 ns = _x.size(); if(ns<3 || _y.size()<=0 || ns!=_y.size()) throw ParmError("InverseFunc::InverseFunc_Error: bad array size"); // Check "x" strictement monotone croissant for(uint_4 i=0;i& xfcty) // Compute table "xfcty" by linear interpolation of "x" versus "y" // on "nout" points from "ymin" to "ymax": // xfcty[i] = interpolation of function "x" for "ymin+i*(ymax-ymin)/(nout-1)" { if(nout<3) return -1; xfcty.resize(nout); long i1,i2; double x; for(int_4 i=0;i& xfcty) { if(nout<3) return -1; xfcty.resize(nout); long i1,i2,i3; double x; for(int_4 i=0;i& X,vector& Y,unsigned short typint) // Interpole in x0 the table Y = f(X) // X doit etre ordonne par ordre croissant (strictement) // typint = 0 : nearest value // 1 : linear interpolation // 2 : parabolique interpolation { long n = X.size(); if(n>(long)Y.size() || n<2) throw ParmError("InterpTab_Error : incompatible size between X and Y tables!"); if(x0X[n-1]) return 0.; if(typint>2) typint = 0; // Recherche des indices encadrants par dichotomie long k, klo=0, khi=n-1; while (khi-klo > 1) { k = (khi+klo) >> 1; if (X[k] > x0) khi=k; else klo=k; } // Quel est le plus proche? k = (x0-X[klo]& v,double xmin,double xmax,bool logaxex) // Remplit le TVector avec la fonction "func" // INPUT: // logaxex = false : remplissage lineaire // les abscisses "x" des bins sont remplis avec f(x) // logaxex = true : remplissage logarithmique (base 10) // les abscisses "x" des bins sont remplis avec f(10^x) // RETURN: // 0 = OK // 1 = error // Remarque: // v(i) = f(xmin+i*dx) avec dx = (xmax-xmin)/v.NElts() { if(v.NElts()<=0 || xmax<=xmin) return 1; v = 0.; double dx = (xmax-xmin)/v.NElts(); for(int_4 i=0;iM_PI) theta2=M_PI; return 2.*dphi * (cos(theta1)-cos(theta2)); } double AngSol(double dtheta) // Retourne l'angle solide d'une calotte spherique de demi-ouverture "dtheta" // Attention: Les unites des angles sont en radians // dtheta in [0,Pi] // Return: l'angle solide en steradian // Approx pour theta petit: PI * theta^2 { return 2.*M_PI * (1.-cos(dtheta)); } double FrAngSol(double angsol) // Retourne la demi-ouverture "dtheta" d'une calotte spherique d'angle solide "angsol" // Input: angle solide de la calotte spherique en steradians // Return: demi-ouverture de la calotte spherique en radians { angsol = 1. - angsol/(2.*M_PI); if(angsol<-1. || angsol>1.) return -1.; return acos(angsol); } //------------------------------------------------------------------- static unsigned short IntegrateFunc_GlOrder = 0; static vector IntegrateFunc_x; static vector IntegrateFunc_w; /////////////////////////////////////////////////////////// //************** Integration of Functions ***************// /////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// double IntegrateFunc(GenericFunc& func,double xmin,double xmax ,double perc,double dxinc,double dxmax,unsigned short glorder) // --- Integration adaptative --- // Integrate[func[x], {x,xmin,xmax}] // ..xmin,xmax are the integration limits // ..dxinc is the searching increment x = xmin+i*dxinc // if <0 npt = int(|dxinc|) (si<2 alors npt=100) // et dxinc = (xmax-xmin)/npt // ..dxmax is the maximum possible increment (if dxmax<=0 no test) // --- // Partition de [xmin,xmax] en intervalles [x(i),x(i+1)]: // on parcourt [xmin,xmax] par pas de "dxinc" : x(i) = xmin + i*dxinc // on cree un intervalle [x(i),x(i+1)] // - si |f[x(i+1)] - f[x(i)]| > perc*|f[[x(i)]| // - si |x(i+1)-x(i)| >= dxmax (si dxmax>0.) // Dans un intervalle [x(i),x(i+1)] la fonction est integree // avec une methode de gauss-legendre d'ordre "glorder" { double signe = 1.; if(xmin>xmax) {double tmp=xmax; xmax=xmin; xmin=tmp; signe=-1.;} if(glorder==0) glorder = 4; if(perc<=0.) perc=0.1; if(dxinc<=0.) {int n=int(-dxinc); if(n<2) n=100; dxinc=(xmax-xmin)/n;} if(glorder != IntegrateFunc_GlOrder) { IntegrateFunc_GlOrder = glorder; Compute_GaussLeg(glorder,IntegrateFunc_x,IntegrateFunc_w,0.,1.); } // Recherche des intervalles [x(i),x(i+1)] int_4 ninter = 0; double sum = 0., xbas=xmin, fbas=func(xbas), fabsfbas=fabs(fbas); for(double x=xmin+dxinc; xxmax ) {doit = true; x=xmax;} else if( dxmax>0. && dx>dxmax ) doit = true; else if( fabs(f-fbas)>perc*fabsfbas ) doit = true; if( ! doit ) continue; double s = 0.; for(unsigned short i=0;ilxmax) {double tmp=lxmax; lxmax=lxmin; lxmin=tmp; signe=-1.;} if(glorder==0) glorder = 4; if(perc<=0.) perc=0.1; if(dlxinc<=0.) {int n=int(-dlxinc); if(n<2) n=100; dlxinc=(lxmax-lxmin)/n;} if(glorder != IntegrateFunc_GlOrder) { IntegrateFunc_GlOrder = glorder; Compute_GaussLeg(glorder,IntegrateFunc_x,IntegrateFunc_w,0.,1.); } // Recherche des intervalles [lx(i),lx(i+1)] int_4 ninter = 0; double sum = 0., lxbas=lxmin, fbas=func(pow(10.,lxbas)), fabsfbas=fabs(fbas); for(double lx=lxmin+dlxinc; lxlxmax ) {doit = true; lx=lxmax;} else if( dlxmax>0. && dlx>dlxmax ) doit = true; else if( fabs(f-fbas)>perc*fabsfbas ) doit = true; if( ! doit ) continue; double s = 0.; for(unsigned short i=0;i