source: Sophya/trunk/Cosmo/SimLSS/geneutils.cc@ 3583

Last change on this file since 3583 was 3500, checked in by cmv, 17 years ago

fct sin(x)/x et sin(n*x)/sin(x) cmv 18/06/2008

File size: 16.5 KB
Line 
1#include "machdefs.h"
2#include <iostream>
3#include <stdlib.h>
4#include <stdio.h>
5#include <string.h>
6#include <math.h>
7#include <vector>
8
9#include "pexceptions.h"
10
11#include "histos.h"
12#include "hisprof.h"
13#include "srandgen.h"
14
15#include "geneutils.h"
16
17namespace SOPHYA {
18
19//-------------------------------------------------------------------
20// Classe d'interpolation lineaire:
21// Le vecteur y a n elements y_i tels que y_i = f(x_i)
22// ou les x_i sont regulierement espaces
23// et x_0=xmin et x_{n-1}=xmax (xmax inclus!)
24InterpFunc::InterpFunc(double xmin,double xmax,vector<double>& y)
25 : _xmin(xmin), _xmax(xmax), _y(y)
26{
27 if(_xmin>=_xmax || _y.size()<=2) { // au moins 3 points!
28 cout<<"InterpFunc::InterpFunc : bad arguments values"<<endl;
29 throw ParmError("InterpFunc::InterpFunc : bad arguments values");
30 }
31 _nm1 = _y.size()-1;
32 _dx = (_xmax-_xmin)/(double)_nm1;
33}
34
35double InterpFunc::Linear(double x,unsigned short& ok)
36{
37 ok=0; if(x<_xmin) ok=1; else if(x>_xmax) ok=2;
38 x -= _xmin;
39 long i = long(x/_dx); // On prend le "i" juste en dessous
40 if(i<0) i=0; else if(i>=_nm1) i=_nm1-1;
41 return _y[i] + (_y[i+1]-_y[i])/_dx*(x-i*_dx);
42}
43
44double InterpFunc::Parab(double x,unsigned short& ok)
45{
46 ok=0; if(x<_xmin) ok=1; else if(x>_xmax) ok=2;
47 x -= _xmin;
48 long i = long(x/_dx+0.5); // On prend le "i" le + proche
49 if(i<1) i=1; else if(i>=_nm1-1) i=_nm1-2;
50 double a = (_y[i+1]-2.*_y[i]+_y[i-1])/(2.*_dx*_dx);
51 double b = (_y[i+1]-_y[i-1])/(2.*_dx);
52 return _y[i] + (x-i*_dx)*(a*(x-i*_dx)+b);
53}
54
55//-------------------------------------------------------------------
56// Classe d'inversion d'une fonction STRICTEMENT MONOTONE CROISSANTE
57//
58// - On part de deux vecteurs x,y de "Nin" elements tels que "y_i = f[x_i]"
59// ou la fonction "f" est strictement monotone croissante:
60// x(i) < x(i+1) et y(i) < y(i+1)
61// - Le but de la classe est de remplir un vecteur X de "Nout" elements
62// tels que: X_j = f^-1[Y_j] avec j=[0,Nout[
63// avec les Y_j regulierement espaces entre ymin=y(0) , ymax=y(Nin -1)
64// cad: X_j = f^-1[ ymin+j*(ymax-ymin)/(Nout-1) ]
65// - La construction du vecteur X est realisee
66// par interpolation lineaire (ComputeLinear) ou parabolique (ComputeParab)
67InverseFunc::InverseFunc(vector<double>& x,vector<double>& y)
68 : _ymin(0.) , _ymax(0.) , _x(x) , _y(y)
69{
70 uint_4 ns = _x.size();
71 if(ns<3 || _y.size()<=0 || ns!=_y.size())
72 throw ParmError("InverseFunc::InverseFunc_Error: bad array size");
73
74 // Check "x" strictement monotone croissant
75 for(uint_4 i=0;i<ns-1;i++)
76 if(_x[i+1]<=_x[i]) {
77 cout<<"InverseFunc::InverseFunc_Error: _x array not stricly growing"<<endl;
78 throw ParmError("InverseFunc::InverseFunc_Error: _x array not stricly growing");
79 }
80
81 // Check "y" monotone croissant
82 for(uint_4 i=0;i<ns-1;i++)
83 if(_y[i+1]<_y[i]) {
84 cout<<"InverseFunc::InverseFunc_Error: _y array not growing"<<endl;
85 throw ParmError("InverseFunc::InverseFunc_Error: _y array not growing");
86 }
87
88 // define limits
89 _ymin = _y[0];
90 _ymax = _y[ns-1];
91
92}
93
94InverseFunc::~InverseFunc(void)
95{
96}
97
98int InverseFunc::ComputeLinear(long nout,vector<double>& xfcty)
99// Compute table "xfcty" by linear interpolation of "x" versus "y"
100// on "nout" points from "ymin" to "ymax":
101// xfcty[i] = interpolation of function "x" for "ymin+i*(ymax-ymin)/(nout-1)"
102{
103 if(nout<3) return -1;
104
105 xfcty.resize(nout);
106
107 long i1,i2;
108 double x;
109 for(int_4 i=0;i<nout;i++) {
110 double y = _ymin + i*(_ymax-_ymin)/(nout-1.);
111 find_in_y(y,i1,i2);
112 double dy = _y[i2]-_y[i1];
113 if(dy==0.) {
114 x = (_x[i2]+_x[i1])/2.; // la fct a inverser est plate!
115 } else {
116 x = _x[i1] + (_x[i2]-_x[i1])/dy * (y-_y[i1]);
117 }
118 xfcty[i] = x;
119 }
120
121 return 0;
122}
123
124int InverseFunc::ComputeParab(long nout,vector<double>& xfcty)
125{
126 if(nout<3) return -1;
127
128 xfcty.resize(nout);
129
130 long i1,i2,i3;
131 double x;
132 for(int_4 i=0;i<nout;i++) {
133 double y = _ymin + i*(_ymax-_ymin)/(nout-1.);
134 find_in_y(y,i1,i2);
135 // On cherche le 3ieme point selon la position de y / au 2 premiers
136 double my = (_y[i1]+_y[i2])/2.;
137 if(y<my) {i3=i2; i2=i1; i1--;} else {i3=i2+1;}
138 // Protection
139 if(i1<0) {i1++; i2++; i3++;}
140 if(i3==(long)_y.size()) {i1--; i2--; i3--;}
141 // Interpolation parabolique
142 double dy = _y[i3]-_y[i1];
143 if(dy==0.) {
144 x = (_x[i3]+_x[i1])/2.; // la fct a inverser est plate!
145 } else {
146 double X1=_x[i1]-_x[i2], X3=_x[i3]-_x[i2];
147 double Y1=_y[i1]-_y[i2], Y3=_y[i3]-_y[i2];
148 double den = Y1*Y3*dy;
149 double a = (X3*Y1-X1*Y3)/den;
150 double b = (X1*Y3*Y3-X3*Y1*Y1)/den;
151 y -= _y[i2];
152 x = (a*y+b)*y + _x[i2];
153 }
154 xfcty[i] = x;
155 }
156
157 return 0;
158}
159
160//----------------------------------------------------
161double InterpTab(double x0,vector<double>& X,vector<double>& Y,unsigned short typint)
162// Interpole in x0 the table Y = f(X)
163// X doit etre ordonne par ordre croissant (strictement)
164// typint = 0 : nearest value
165// 1 : linear interpolation
166// 2 : parabolique interpolation
167{
168 long n = X.size();
169 if(n>(long)Y.size() || n<2)
170 throw ParmError("InterpTab_Error : incompatible size between X and Y tables!");
171
172 if(x0<X[0] || x0>X[n-1]) return 0.;
173 if(typint>2) typint = 0;
174
175 // Recherche des indices encadrants par dichotomie
176 long k, klo=0, khi=n-1;
177 while (khi-klo > 1) {
178 k = (khi+klo) >> 1;
179 if (X[k] > x0) khi=k; else klo=k;
180 }
181
182 // Quel est le plus proche?
183 k = (x0-X[klo]<X[khi]-x0) ? klo: khi;
184
185 // On retourne le plus proche
186 if(typint==0) return Y[k];
187
188 // On retourne l'extrapolation lineaire
189 if(typint==1 || n<3)
190 return Y[klo] + (Y[khi]-Y[klo])/(X[khi]-X[klo])*(x0-X[klo]);
191
192 // On retourne l'extrapolation parabolique
193 if(k==0) k++; else if(k==n-1) k--;
194 klo = k-1; khi = k+1;
195 double x1 = X[klo]-X[k], x2 = X[khi]-X[k];
196 double y1 = Y[klo]-Y[k], y2 = Y[khi]-Y[k];
197 double den = x1*x2*(x1-x2);
198 double a = (y1*x2-y2*x1)/den;
199 double b = (y2*x1*x1-y1*x2*x2)/den;
200 x0 -= X[k];
201 return Y[k] + (a*x0+b)*x0;;
202
203}
204
205//-------------------------------------------------------------------
206int FuncToHisto(GenericFunc& func,Histo& h,bool logaxex)
207// Remplit l'histo 1D "h" avec la fonction "func"
208// INPUT:
209// logaxex = false : remplissage lineaire
210// les abscisses "x" des bins sont remplis avec f(x)
211// logaxex = true : remplissage logarithmique (base 10)
212// les abscisses "x" des bins sont remplis avec f(10^x)
213// RETURN:
214// 0 = OK
215// 1 = error
216{
217 if(h.NBins()<=0) return 1;
218
219 h.Zero();
220
221 for(int_4 i=0;i<h.NBins();i++) {
222 double x = h.BinCenter(i);
223 if(logaxex) x = pow(10.,x);
224 h.SetBin(i,func(x));
225 }
226
227 return 0;
228}
229
230int FuncToVec(GenericFunc& func,TVector<r_8>& v,double xmin,double xmax,bool logaxex)
231// Remplit le TVector avec la fonction "func"
232// INPUT:
233// logaxex = false : remplissage lineaire
234// les abscisses "x" des bins sont remplis avec f(x)
235// logaxex = true : remplissage logarithmique (base 10)
236// les abscisses "x" des bins sont remplis avec f(10^x)
237// RETURN:
238// 0 = OK
239// 1 = error
240// Remarque:
241// v(i) = f(xmin+i*dx) avec dx = (xmax-xmin)/v.NElts()
242{
243 if(v.NElts()<=0 || xmax<=xmin) return 1;
244
245 v = 0.;
246 double dx = (xmax-xmin)/v.NElts();
247
248 for(int_4 i=0;i<v.NElts();i++) {
249 double x = xmin + i * dx;;
250 if(logaxex) x = pow(10.,x);
251 v(i) = func(x);
252 }
253
254 return 0;
255}
256
257//-------------------------------------------------------------------
258double AngSol(double dtheta,double dphi,double theta0)
259// Retourne l'angle solide d'un "rectangle" et coordonnees spheriques
260// de DEMI-COTE "dtheta" x "dphi" et centre en "theta0"
261// Attention: Le "theta0" de l'equateur est Pi/2 (et non pas zero)
262// Les unites des angles sont en radians
263// theta0 in [0,Pi]
264// dtheta in [0,Pi]
265// dphi in [0,2Pi]
266// Return: l'angle solide en steradian
267{
268 double theta1 = theta0-dtheta, theta2 = theta0+dtheta;
269 if(theta1<0.) theta1=0.;
270 if(theta2>M_PI) theta2=M_PI;
271
272 return 2.*dphi * (cos(theta1)-cos(theta2));
273}
274
275double AngSol(double dtheta)
276// Retourne l'angle solide d'une calotte spherique de demi-ouverture "dtheta"
277// Attention: Les unites des angles sont en radians
278// dtheta in [0,Pi]
279// Return: l'angle solide en steradian
280// Approx pour theta petit: PI * theta^2
281{
282 return 2.*M_PI * (1.-cos(dtheta));
283}
284
285double FrAngSol(double angsol)
286// Retourne la demi-ouverture "dtheta" d'une calotte spherique d'angle solide "angsol"
287// Input: angle solide de la calotte spherique en steradians
288// Return: demi-ouverture de la calotte spherique en radians
289{
290 angsol = 1. - angsol/(2.*M_PI);
291 if(angsol<-1. || angsol>1.) return -1.;
292 return acos(angsol);
293}
294
295//-------------------------------------------------------------------
296double SinXsX(double x,bool app)
297// Calcul de sin(x)/x
298// Approx: dernier terme x^6/(6*20*42) ~ 1e-13 -> x^2 ~ 1.7e-4
299{
300 double x2 = x*x;
301 if(app || x2<1.7e-4) return 1. - x2/6.*(1. - x2/20.*(1. - x2/42.));
302 return sin(x)/x;
303}
304
305double SinXsX_Sqr(double x,bool app)
306// Calcul de (sin(x)/x)^2
307// Approx: dernier terme 2*x^6/(3*15*14) ~ 1e-13 -> x^2 ~ 6.8e-5
308{
309 double x2 = x*x;
310 if(app || x2<6.8e-5) return 1. - x2/3.*(1. - 2.*x2/15.*(1. - x2/14.));
311 x2 = sin(x)/x;
312 return x2*x2;
313}
314
315double SinNXsX(double x,unsigned long N,bool app)
316// Calcul de sin(N*x)/sin(x) avec N entier positif
317// ATTENTION: N est entier
318// 1. pour que sin(N*x) et sin(x) soient nuls en meme temps
319// (on peut faire le DL popur sin(N*x) et sin(x))
320// 2. pour traiter correctement le DL en x = p*Pi+e avec e<<1 et p entier
321// sin(N*x)/sin(x) = sin(N*p*Pi+N*e)/sin(p*Pi+e)
322// = [sin(N*p*Pi)*cos(N*e)+cos(N*p*Pi)*sin(N*e)]
323// / [sin(p*Pi)*cos(e)+cos(p*Pi)*sin(e)]
324// comme sin(N*p*Pi)=0
325// = [cos(N*p*Pi)*sin(N*e)] / [cos(p*Pi)*sin(e)]
326// = [sin(N*e)/sin(e)] * [cos(N*p*Pi)/cos(p*Pi)]
327// = [DL autour de x=0] * (+1 ou -1)
328// Le seul cas ou on a "-1" est quand "p=impair" (cos(p*Pi)=-1) et "N=pair"
329// Approx: dernier terme x^4*N^4/120 ~ 1e-13 -> x^2 ~ 3.5e-6/N^2
330{
331 if(N==0) return 0;
332 double sx = sin(x), N2 = N*N;
333 if(app || sx*sx<3.5e-6/N2) {
334 double x2 = asin(sx); x2 *= x2;
335 double s = 1.;
336 if(N%2==0 && cos(x)<0.) s = -1.; // cas x ~ (2p+1)*Pi et N pair
337 return s*N*(1.-(N-1.)*(N+1.)/6.*x2*(1.-(3.*N2-7.)/60.*x2));
338 }
339 return sin((double)N*x)/sx;
340}
341
342double SinNXsX_Sqr(double x,unsigned long N,bool app)
343// Calcul de [sin(N*x)/sin(x)]^2 avec N entier positif
344// ATTENTION: cf remarque pour N entier dans SinNXsX
345// Approx: dernier terme x^4*2*N^4/45 ~ 1e-13 -> x^2 ~ 1.5e-6/N^2
346{
347 if(N==0) return 0;
348 double sx = sin(x), N2 = N*N;
349 if(app || sx*sx<1.5e-6/N2) {
350 double x2 = asin(sx); x2 *= x2;
351 return N2*(1. - (N-1.)*(N+1.)/3.*x2*(1. - (2.*N2-3.)/15.*x2));
352 }
353 sx = sin((double)N*x)/sx;
354 return sx*sx;
355}
356
357//-------------------------------------------------------------------
358
359static unsigned short IntegrateFunc_GlOrder = 0;
360static vector<double> IntegrateFunc_x;
361static vector<double> IntegrateFunc_w;
362
363///////////////////////////////////////////////////////////
364//************** Integration of Functions ***************//
365///////////////////////////////////////////////////////////
366
367
368////////////////////////////////////////////////////////////////////////////////////
369double IntegrateFunc(GenericFunc& func,double xmin,double xmax
370 ,double perc,double dxinc,double dxmax,unsigned short glorder)
371// --- Integration adaptative ---
372// Integrate[func[x], {x,xmin,xmax}]
373// ..xmin,xmax are the integration limits
374// ..dxinc is the searching increment x = xmin+i*dxinc
375// if <0 npt = int(|dxinc|) (si<2 alors npt=100)
376// et dxinc = (xmax-xmin)/npt
377// ..dxmax is the maximum possible increment (if dxmax<=0 no test)
378// ---
379// Partition de [xmin,xmax] en intervalles [x(i),x(i+1)]:
380// on parcourt [xmin,xmax] par pas de "dxinc" : x(i) = xmin + i*dxinc
381// on cree un intervalle [x(i),x(i+1)]
382// - si |f[x(i+1)] - f[x(i)]| > perc*|f[[x(i)]|
383// - si |x(i+1)-x(i)| >= dxmax (si dxmax>0.)
384// Dans un intervalle [x(i),x(i+1)] la fonction est integree
385// avec une methode de gauss-legendre d'ordre "glorder"
386{
387 double signe = 1.;
388 if(xmin>xmax) {double tmp=xmax; xmax=xmin; xmin=tmp; signe=-1.;}
389
390 if(glorder==0) glorder = 4;
391 if(perc<=0.) perc=0.1;
392 if(dxinc<=0.) {int n=int(-dxinc); if(n<2) n=100; dxinc=(xmax-xmin)/n;}
393 if(glorder != IntegrateFunc_GlOrder) {
394 IntegrateFunc_GlOrder = glorder;
395 Compute_GaussLeg(glorder,IntegrateFunc_x,IntegrateFunc_w,0.,1.);
396 }
397
398 // Recherche des intervalles [x(i),x(i+1)]
399 int_4 ninter = 0;
400 double sum = 0., xbas=xmin, fbas=func(xbas), fabsfbas=fabs(fbas);
401 for(double x=xmin+dxinc; x<xmax+dxinc/2.; x += dxinc) {
402 double f = func(x);
403 double dx = x-xbas;
404 bool doit = false;
405 if( x>xmax ) {doit = true; x=xmax;}
406 else if( dxmax>0. && dx>dxmax ) doit = true;
407 else if( fabs(f-fbas)>perc*fabsfbas ) doit = true;
408 if( ! doit ) continue;
409 double s = 0.;
410 for(unsigned short i=0;i<IntegrateFunc_GlOrder;i++)
411 s += IntegrateFunc_w[i]*func(xbas+IntegrateFunc_x[i]*dx);
412 sum += s*dx;
413 xbas = x; fbas = f; fabsfbas=fabs(fbas); ninter++;
414 }
415 //cout<<"Ninter="<<ninter<<endl;
416
417 return sum*signe;
418}
419
420////////////////////////////////////////////////////////////////////////////////////
421double IntegrateFuncLog(GenericFunc& func,double lxmin,double lxmax
422 ,double perc,double dlxinc,double dlxmax,unsigned short glorder)
423// --- Integration adaptative ---
424// Idem IntegrateFunc but integrate on logarithmic (base 10) intervals:
425// Int[ f(x) dx ] = Int[ x*f(x) dlog10(x) ] * log(10)
426// ..lxmin,lxmax are the log10() of the integration limits
427// ..dlxinc is the searching logarithmic (base 10) increment lx = lxmin+i*dlxinc
428// ..dlxmax is the maximum possible logarithmic (base 10) increment (if dlxmax<=0 no test)
429// Remarque: to be use if "x*f(x) versus log10(x)" looks like a polynomial
430// better than "f(x) versus x"
431// ATTENTION: la fonction func que l'on passe en argument
432// est "func(x)" et non pas "func(log10(x))"
433{
434 double signe = 1.;
435 if(lxmin>lxmax) {double tmp=lxmax; lxmax=lxmin; lxmin=tmp; signe=-1.;}
436
437 if(glorder==0) glorder = 4;
438 if(perc<=0.) perc=0.1;
439 if(dlxinc<=0.) {int n=int(-dlxinc); if(n<2) n=100; dlxinc=(lxmax-lxmin)/n;}
440 if(glorder != IntegrateFunc_GlOrder) {
441 IntegrateFunc_GlOrder = glorder;
442 Compute_GaussLeg(glorder,IntegrateFunc_x,IntegrateFunc_w,0.,1.);
443 }
444
445 // Recherche des intervalles [lx(i),lx(i+1)]
446 int_4 ninter = 0;
447 double sum = 0., lxbas=lxmin, fbas=func(pow(10.,lxbas)), fabsfbas=fabs(fbas);
448 for(double lx=lxmin+dlxinc; lx<lxmax+dlxinc/2.; lx += dlxinc) {
449 double f = func(pow(10.,lx));
450 double dlx = lx-lxbas;
451 bool doit = false;
452 if( lx>lxmax ) {doit = true; lx=lxmax;}
453 else if( dlxmax>0. && dlx>dlxmax ) doit = true;
454 else if( fabs(f-fbas)>perc*fabsfbas ) doit = true;
455 if( ! doit ) continue;
456 double s = 0.;
457 for(unsigned short i=0;i<IntegrateFunc_GlOrder;i++) {
458 double y = pow(10.,lxbas+IntegrateFunc_x[i]*dlx);
459 s += IntegrateFunc_w[i]*y*func(y);
460 }
461 sum += s*dlx;
462 lxbas = lx; fbas = f; fabsfbas=fabs(fbas); ninter++;
463 }
464 //cout<<"Ninter="<<ninter<<endl;
465
466 return M_LN10*sum*signe;
467}
468
469////////////////////////////////////////////////////////////////////////////////////
470/*
471Integration des fonctions a une dimension y=f(x) par la Methode de Gauss-Legendre.
472 --> Calcul des coefficients du developpement pour [x1,x2]
473| INPUT:
474| x1,x2 : bornes de l'intervalle (dans nbinteg.h -> x1=-0.5 x2=0.5)
475| glorder = degre n du developpement de Gauss-Legendre
476| OUTPUT:
477| x[] = valeur des abscisses ou l'on calcule (dim=n)
478| w[] = valeur des coefficients associes
479| REMARQUES:
480| - x et w seront dimensionnes a n.
481| - l'integration est rigoureuse si sur l'intervalle d'integration
482| la fonction f(x) peut etre approximee par un polynome
483| de degre 2*m (monome le + haut x**(2*n-1) )
484*/
485void Compute_GaussLeg(unsigned short glorder,vector<double>& x,vector<double>& w,double x1,double x2)
486{
487 if(glorder==0) return;
488 int n = (int)glorder;
489 x.resize(n,0.); w.resize(n,0.);
490
491 int m,j,i;
492 double z1,z,xm,xl,pp,p3,p2,p1;
493
494 m=(n+1)/2;
495 xm=0.5*(x2+x1);
496 xl=0.5*(x2-x1);
497 for (i=1;i<=m;i++) {
498 z=cos(M_PI*(i-0.25)/(n+0.5));
499 do {
500 p1=1.0;
501 p2=0.0;
502 for (j=1;j<=n;j++) {
503 p3=p2;
504 p2=p1;
505 p1=((2.0*j-1.0)*z*p2-(j-1.0)*p3)/j;
506 }
507 pp=n*(z*p1-p2)/(z*z-1.0);
508 z1=z;
509 z=z1-p1/pp;
510 } while (fabs(z-z1) > 3.0e-11); // epsilon
511 x[i-1]=xm-xl*z;
512 x[n-i]=xm+xl*z;
513 w[i-1]=2.0*xl/((1.0-z*z)*pp*pp);
514 w[n-i]=w[i-1];
515 }
516}
517
518} // Fin namespace SOPHYA
Note: See TracBrowser for help on using the repository browser.