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

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

Intro raffinement dans simul AGN, variation dNu Da Dlum selon Oz cmv 05/04/2007

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