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

Last change on this file since 3196 was 3196, checked in by cmv, 18 years ago

les AGN selon C.Jackson, une premiere approche simplifiee, recodage from Jim Rich. cmv 03/04/2007

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