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

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

intro ComputeSpectrum avec soustraction de bruit et deconvolution par la fct de transfert du pixel cmv 01/10/2007

File size: 14.4 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
285//-------------------------------------------------------------------
286unsigned long PoissRandLimit(double mu,double mumax)
287{
288 double pp,ppi,x;
289 unsigned long n;
290
291 if(mu>=mumax) {
292 pp = sqrt(mu);
293 while( (x=pp*NorRand()) < -mu );
294 return (unsigned long)(mu+x+0.5);
295 }
296
297 ppi = pp = exp(-mu);
298 x = drand01();
299 n = 0;
300 while (x > ppi) {
301 n++;
302 pp = mu*pp/(double)n;
303 ppi += pp;
304 }
305 return n;
306}
307
308//-------------------------------------------------------------------
309
310static unsigned short IntegrateFunc_GlOrder = 0;
311static vector<double> IntegrateFunc_x;
312static vector<double> IntegrateFunc_w;
313
314///////////////////////////////////////////////////////////
315//************** Integration of Functions ***************//
316///////////////////////////////////////////////////////////
317
318
319////////////////////////////////////////////////////////////////////////////////////
320double IntegrateFunc(GenericFunc& func,double xmin,double xmax
321 ,double perc,double dxinc,double dxmax,unsigned short glorder)
322// --- Integration adaptative ---
323// Integrate[func[x], {x,xmin,xmax}]
324// ..xmin,xmax are the integration limits
325// ..dxinc is the searching increment x = xmin+i*dxinc
326// if <0 npt = int(|dxinc|) (si<2 alors npt=100)
327// et dxinc = (xmax-xmin)/npt
328// ..dxmax is the maximum possible increment (if dxmax<=0 no test)
329// ---
330// Partition de [xmin,xmax] en intervalles [x(i),x(i+1)]:
331// on parcourt [xmin,xmax] par pas de "dxinc" : x(i) = xmin + i*dxinc
332// on cree un intervalle [x(i),x(i+1)]
333// - si |f[x(i+1)] - f[x(i)]| > perc*|f[[x(i)]|
334// - si |x(i+1)-x(i)| >= dxmax (si dxmax>0.)
335// Dans un intervalle [x(i),x(i+1)] la fonction est integree
336// avec une methode de gauss-legendre d'ordre "glorder"
337{
338 double signe = 1.;
339 if(xmin>xmax) {double tmp=xmax; xmax=xmin; xmin=tmp; signe=-1.;}
340
341 if(glorder==0) glorder = 4;
342 if(perc<=0.) perc=0.1;
343 if(dxinc<=0.) {int n=int(-dxinc); if(n<2) n=100; dxinc=(xmax-xmin)/n;}
344 if(glorder != IntegrateFunc_GlOrder) {
345 IntegrateFunc_GlOrder = glorder;
346 Compute_GaussLeg(glorder,IntegrateFunc_x,IntegrateFunc_w,0.,1.);
347 }
348
349 // Recherche des intervalles [x(i),x(i+1)]
350 int_4 ninter = 0;
351 double sum = 0., xbas=xmin, fbas=func(xbas), fabsfbas=fabs(fbas);
352 for(double x=xmin+dxinc; x<xmax+dxinc/2.; x += dxinc) {
353 double f = func(x);
354 double dx = x-xbas;
355 bool doit = false;
356 if( x>xmax ) {doit = true; x=xmax;}
357 else if( dxmax>0. && dx>dxmax ) doit = true;
358 else if( fabs(f-fbas)>perc*fabsfbas ) doit = true;
359 if( ! doit ) continue;
360 double s = 0.;
361 for(unsigned short i=0;i<IntegrateFunc_GlOrder;i++)
362 s += IntegrateFunc_w[i]*func(xbas+IntegrateFunc_x[i]*dx);
363 sum += s*dx;
364 xbas = x; fbas = f; fabsfbas=fabs(fbas); ninter++;
365 }
366 //cout<<"Ninter="<<ninter<<endl;
367
368 return sum*signe;
369}
370
371////////////////////////////////////////////////////////////////////////////////////
372double IntegrateFuncLog(GenericFunc& func,double lxmin,double lxmax
373 ,double perc,double dlxinc,double dlxmax,unsigned short glorder)
374// --- Integration adaptative ---
375// Idem IntegrateFunc but integrate on logarithmic (base 10) intervals:
376// Int[ f(x) dx ] = Int[ x*f(x) dlog10(x) ] * log(10)
377// ..lxmin,lxmax are the log10() of the integration limits
378// ..dlxinc is the searching logarithmic (base 10) increment lx = lxmin+i*dlxinc
379// ..dlxmax is the maximum possible logarithmic (base 10) increment (if dlxmax<=0 no test)
380// Remarque: to be use if "x*f(x) versus log10(x)" looks like a polynomial
381// better than "f(x) versus x"
382// ATTENTION: la fonction func que l'on passe en argument
383// est "func(x)" et non pas "func(log10(x))"
384{
385 double signe = 1.;
386 if(lxmin>lxmax) {double tmp=lxmax; lxmax=lxmin; lxmin=tmp; signe=-1.;}
387
388 if(glorder==0) glorder = 4;
389 if(perc<=0.) perc=0.1;
390 if(dlxinc<=0.) {int n=int(-dlxinc); if(n<2) n=100; dlxinc=(lxmax-lxmin)/n;}
391 if(glorder != IntegrateFunc_GlOrder) {
392 IntegrateFunc_GlOrder = glorder;
393 Compute_GaussLeg(glorder,IntegrateFunc_x,IntegrateFunc_w,0.,1.);
394 }
395
396 // Recherche des intervalles [lx(i),lx(i+1)]
397 int_4 ninter = 0;
398 double sum = 0., lxbas=lxmin, fbas=func(pow(10.,lxbas)), fabsfbas=fabs(fbas);
399 for(double lx=lxmin+dlxinc; lx<lxmax+dlxinc/2.; lx += dlxinc) {
400 double f = func(pow(10.,lx));
401 double dlx = lx-lxbas;
402 bool doit = false;
403 if( lx>lxmax ) {doit = true; lx=lxmax;}
404 else if( dlxmax>0. && dlx>dlxmax ) doit = true;
405 else if( fabs(f-fbas)>perc*fabsfbas ) doit = true;
406 if( ! doit ) continue;
407 double s = 0.;
408 for(unsigned short i=0;i<IntegrateFunc_GlOrder;i++) {
409 double y = pow(10.,lxbas+IntegrateFunc_x[i]*dlx);
410 s += IntegrateFunc_w[i]*y*func(y);
411 }
412 sum += s*dlx;
413 lxbas = lx; fbas = f; fabsfbas=fabs(fbas); ninter++;
414 }
415 //cout<<"Ninter="<<ninter<<endl;
416
417 return M_LN10*sum*signe;
418}
419
420////////////////////////////////////////////////////////////////////////////////////
421/*
422Integration des fonctions a une dimension y=f(x) par la Methode de Gauss-Legendre.
423 --> Calcul des coefficients du developpement pour [x1,x2]
424| INPUT:
425| x1,x2 : bornes de l'intervalle (dans nbinteg.h -> x1=-0.5 x2=0.5)
426| glorder = degre n du developpement de Gauss-Legendre
427| OUTPUT:
428| x[] = valeur des abscisses ou l'on calcule (dim=n)
429| w[] = valeur des coefficients associes
430| REMARQUES:
431| - x et w seront dimensionnes a n.
432| - l'integration est rigoureuse si sur l'intervalle d'integration
433| la fonction f(x) peut etre approximee par un polynome
434| de degre 2*m (monome le + haut x**(2*n-1) )
435*/
436void Compute_GaussLeg(unsigned short glorder,vector<double>& x,vector<double>& w,double x1,double x2)
437{
438 if(glorder==0) return;
439 int n = (int)glorder;
440 x.resize(n,0.); w.resize(n,0.);
441
442 int m,j,i;
443 double z1,z,xm,xl,pp,p3,p2,p1;
444
445 m=(n+1)/2;
446 xm=0.5*(x2+x1);
447 xl=0.5*(x2-x1);
448 for (i=1;i<=m;i++) {
449 z=cos(M_PI*(i-0.25)/(n+0.5));
450 do {
451 p1=1.0;
452 p2=0.0;
453 for (j=1;j<=n;j++) {
454 p3=p2;
455 p2=p1;
456 p1=((2.0*j-1.0)*z*p2-(j-1.0)*p3)/j;
457 }
458 pp=n*(z*p1-p2)/(z*z-1.0);
459 z1=z;
460 z=z1-p1/pp;
461 } while (fabs(z-z1) > 3.0e-11); // epsilon
462 x[i-1]=xm-xl*z;
463 x[n-i]=xm+xl*z;
464 w[i-1]=2.0*xl/((1.0-z*z)*pp*pp);
465 w[n-i]=w[i-1];
466 }
467}
468
469} // Fin namespace SOPHYA
Note: See TracBrowser for help on using the repository browser.