source: Sophya/trunk/SophyaLib/NTools/generalfit.cc@ 938

Last change on this file since 938 was 938, checked in by ansari, 25 years ago

Vector,Matrix -> TVector,TMatrix<r_8> cmv 14/4/00

File size: 48.7 KB
Line 
1#include "machdefs.h"
2#include <stdio.h>
3#include <stdlib.h>
4#include <iostream.h>
5#include <math.h>
6#ifdef __MWERKS__
7 #include "mwerksmath.h" // Portage mac D. Y.
8#include "unixmac.h"
9#endif
10#include <string.h>
11#include <string>
12
13#include "pexceptions.h"
14#include "generalfit.h"
15#include "sopemtx.h"
16
17#define EPS_FIT_MIN 1.e-8
18
19//================================================================
20// GeneralFunction
21//================================================================
22
23/*!
24 \class SOPHYA::GeneralFunction
25 \ingroup NTools
26 Classe de fonctions parametrees a plusieurs variables:
27 \f$ F[x1,x2,x3,...:a1,a2,a3,...] \f$
28*/
29
30//////////////////////////////////////////////////////////////////////
31/*!
32 Creation d'une fonction de `nVar' variables et `nPar' parametres:
33 \f$ F[x(1),x(2),x(3),...x(nVar) : a(1),a(2),a(3),...,a(nPar)] \f$
34*/
35GeneralFunction::GeneralFunction(unsigned int nVar, unsigned int nPar)
36 : mNVar(nVar), mNPar(nPar)
37{
38 ASSERT( nVar > 0 && nPar > 0 );
39 deltaParm = new double[nPar];
40 tmpParm = new double[nPar];
41 END_CONSTRUCTOR
42}
43
44GeneralFunction::~GeneralFunction()
45{
46 delete[] deltaParm;
47 delete[] tmpParm;
48}
49
50//////////////////////////////////////////////////////////////////////
51/*!
52 Valeur et Derivees de la fonction (fct virtuelle par defaut).
53*/
54double GeneralFunction::Val_Der(double const xp[], double const* parm
55 , double *DgDpar)
56{
57 for(int i=0;i<mNPar;i++) tmpParm[i] = parm[i];
58 {for(int i=0;i<mNPar;i++) {
59 double d = deltaParm[i];
60 if(d==0.) { DgDpar[i] = 0.; continue;}
61 tmpParm[i] -= d/2.;
62 double vg = Value(xp,tmpParm);
63 tmpParm[i] += d;
64 double vd = Value(xp,tmpParm);
65 DgDpar[i] = (vd - vg)/d;
66 tmpParm[i] = parm[i];
67 }}
68 return Value(xp, parm);
69}
70
71//////////////////////////////////////////////////////////////////////
72/*!
73 Definition de la variation du parametre numPar
74 pour calculer la derivee automatiquement.
75*/
76void GeneralFunction::SetDeltaParm(int numPar, double d)
77{
78 ASSERT(numPar >= 0 && numPar < mNPar);
79 deltaParm[numPar] = d;
80}
81
82
83/*!
84 Idem precedente fonction mais pour tous les parametres
85*/
86void GeneralFunction::SetDeltaParm(double const* dparam)
87{
88 for(int i=0;i<mNPar;i++) deltaParm[i] = dparam[i];
89}
90
91//================================================================
92// GeneralFunc
93//================================================================
94
95/*!
96 \class SOPHYA::GeneralFunc
97 \ingroup NTools
98 Classe de fonctions parametrees a plusieurs variables
99 derivant de ``GeneralFunction''. Permet de definir
100 une fonction a fiter sans passer par une classe derivee
101 en utilisant l'ecriture courante du C. La fonction
102 retournant les derivees par rapport aux parametres du fit
103 peut etre egalement fournie (optionnel).
104*/
105
106/////////////////////////////////////////////////////////////////
107/*!
108 Createur, on passe le nom ``fun'' de la fonction a la mode C.
109 On peut optionellement egalement passer le nom de la fonction
110 ``funder'' qui retourne les valeurs des derivees par rapport
111 aux parametres du fit.
112 \verbatim
113 ----------------------
114 Exemple d'utilisation:
115 ----------------------
116 include "generalfit.h"
117 ...
118 double gaussc(double const* x,double const* p);
119 double d_gaussc(double const* x,double const* p,double* dp);
120 ...
121 main {
122 ...
123 // Fit SANS calcul automatique des derivees
124 GeneralFunc myfunc(2,7,gaussc);
125 GeneralFit myfit(&myfunc);
126 ...
127 myfit.Fit();
128 ...
129 // Fit AVEC calcul automatique des derivees
130 GeneralFunc myfunc(2,7,gaussc,d_gaussc);
131 GeneralFit myfit(&myfunc);
132 ...
133 myfit.Fit();
134 }
135 // Definition de la fonction a fitter a la mode C
136 double gaussc(double const* x,double const* p)
137 // Fonction: X=(x[0]-p[1])/p[3], Y=(x[1]-p[2])/p[4],
138 // f = p[0]*exp{-0.5*[X^2+Y^2-2*p[5]*X*Y]} + p[6]
139 {
140 double X = (x[0]-p[1])/p[3];
141 double Y = (x[1]-p[2])/p[4];
142 return p[0]*exp(-(X*X+Y*Y-2*p[5]*X*Y)/2)+p[6];
143 }
144 // Definition de la fonction des derivees / parametres
145 // Cette fonction retourne aussi la valeur de la fonction a fitter.
146 double d_gaussc(double const* x,double const* p,double* dp)
147 {
148 dp[0] = derivee de gaussc par rapport au parametre p[0]
149 ...
150 dp[6] = derivee de gaussc par rapport au parametre p[6]
151 return gaussc(x,p);
152 }
153 \endverbatim
154*/
155GeneralFunc::GeneralFunc(unsigned int nvar, unsigned int npar
156 , double (*fun) (double const*, double const*)
157 , double (*funder) (double const*, double const*, double*) )
158: GeneralFunction(nvar,npar), tmpFun(fun), tmpFunDer(funder)
159{
160}
161
162GeneralFunc::~GeneralFunc()
163{
164}
165
166double GeneralFunc::Value(double const xp[], double const* Par)
167{
168return tmpFun(xp,Par);
169}
170
171double GeneralFunc::Val_Der(double const xp[],double const* parm, double* DgDpar)
172{
173if(tmpFunDer) return tmpFunDer(xp,parm,DgDpar);
174 else return GeneralFunction::Val_Der(xp,parm,DgDpar);
175}
176
177//================================================================
178// GeneralXi2
179//================================================================
180
181/*!
182 \class SOPHYA::GeneralXi2
183 \ingroup NTools
184 Classe de Xi2 a plusieurs parametres :
185 \f$ Xi2[a1,a2,a3,...] \f$
186*/
187
188//////////////////////////////////////////////////////////////////////
189/*!
190//
191 Creation d'un Xi2 de `nPar' parametres.
192 \f$ Xi2[a(1),a(2),a(3),...,a(nPar)] \f$
193*/
194GeneralXi2::GeneralXi2(unsigned int nPar)
195 : mNPar(nPar)
196{
197 ASSERT( nPar>0 );
198 deltaParm = new double[nPar];
199 END_CONSTRUCTOR
200}
201
202GeneralXi2::~GeneralXi2()
203{
204 delete[] deltaParm;
205}
206
207//////////////////////////////////////////////////////////////////////
208/*!
209 Derivee du Xi2 par rapport au parametre `i'
210 pour les valeurs `parm' des parametres.
211*/
212double GeneralXi2::Derivee(GeneralFitData& data, int i, double* parm)
213{
214 int dum;
215 double d = deltaParm[i];
216 parm[i] -= d/2.;
217 double vg = Value(data, parm,dum);
218 parm[i] += d;
219 double vd = Value(data, parm,dum);
220 parm[i] -= d/2.;
221 return (vd - vg)/d;
222}
223
224/*!
225 Derivee seconde du Xi2 par rapport aux parametres `i' et `j'
226 pour les valeurs `parm' des parametres. Attention, cette fonction
227 calcule d/di(dC2/dj), valeur qui est numeriquement differente
228 de d/dj(dC2/di).
229 \verbatim
230
231 **** Remarque: Derivee2 = dXi2/dPi.dPj represente le Hessien.
232 Derivee2(k,l)= dXi2/dPk.dPl
233 = 2*SUMi{1/Si^2*[df(xi;P)/dPk * df(xi;P)/dPl]
234 + [yi-f(xi;P)] * df(xi;P)/dPk.dPl }
235 ou (xi,yi) sont les points de mesure. "Si" l'erreur sur le point i
236 SUMi represente la somme sur les points de mesure
237 f(x;P) represente le modele parametrique a fitter
238 "P" represente l'ensemble des parametres et "Pi" le ieme parametre
239 Les composantes du Hessien dependent des derivees 1ere et 2sd du modele
240 a fitter f(x;P) selon les parametres "Pi". La prise en compte des derivees
241 secondes est un facteur destabilisant. De plus le facteur [yi-f(xi;P)]
242 devant la derivee 2sd est seulement l'erreur de mesure aleatoire qui
243 n'est pas correlee avec le modele. Le terme avec la derivee 2sd
244 tend donc a s'annuler et peut donc etre omis.
245 (cf. Numerical Recipes in C, chap 15 Modeling of Data, Nonlinear Models,
246 Calculation of the Gradient and Hessian p682,683)
247
248 **** Conseil: Il est conseille a l'utilisateur de sur-ecrire
249 la fonction virtuelle Derivee2 et de la remplacer par:
250 Derivee2(k,l) = 2*SUMi{1/Si^2*[df(xi;P)/dPk * df(xi;P)/dPl]}
251 \endverbatim
252*/
253double GeneralXi2::Derivee2(GeneralFitData& data, int i, int j, double* parm)
254{
255 double d = deltaParm[i];
256 parm[i] -= d/2.;
257 double vg = Derivee(data,j,parm);
258 parm[i] += d;
259 double vd = Derivee(data,j,parm);
260 parm[i] -= d/2.;
261 d = (vd - vg)/d;
262 return d;
263}
264
265//////////////////////////////////////////////////////////////////////
266/*!
267 Definition de la variation 'd' du parametre 'numPar'
268 pour calculer la derivee automatiquement.
269*/
270void GeneralXi2::SetDeltaParm(int numPar, double d)
271{
272 ASSERT(numPar >= 0 && numPar < mNPar);
273
274 deltaParm[numPar] = d;
275}
276
277/*!
278 Idem precedente fonction mais pour tous les parametres.
279*/
280void GeneralXi2::SetDeltaParm(double const* dparam)
281{
282 for(int i=0;i<mNPar;i++) deltaParm[i] = dparam[i];
283}
284
285//================================================================
286// GeneralFit
287//================================================================
288// Christophe 8/11/93 La Silla
289// re-codage C++ 16/01/96 Saclay
290
291/*!
292 \class SOPHYA::GeneralFit
293 \ingroup NTools
294 Classe de fit d'une GeneralFunction sur une GeneralFitData
295 */
296
297//////////////////////////////////////////////////////////////////////
298/*!
299 Creation d'une classe de fit pour la `GeneralFunction f'.
300*/
301GeneralFit::GeneralFit(GeneralFunction* f)
302 : mNVar (f->NVar()),
303 mNPar (f->NPar()),
304 mFunction (f),
305 mFuncXi2 (NULL),
306
307 Param (f->NPar()),
308 errParam (f->NPar()),
309 stepParam (f->NPar()),
310 minParam (f->NPar()),
311 maxParam (f->NPar()),
312 minStepDeriv (f->NPar()),
313 Eps (f->NPar()),
314
315 ATGA (f->NPar(), f->NPar()),
316 BETA (f->NPar()),
317 ATGA_Try (f->NPar(), f->NPar()),
318 BETA_Try (f->NPar()),
319 C (f->NPar()),
320 D (f->NPar())
321{
322 ASSERT(mNVar>0 && mNPar>0);
323 ASSERT(mNPar<1000000);
324
325 TRY {
326 General_Init();
327 } CATCHALL {
328 THROW_SAME;
329 } ENDTRY
330
331 END_CONSTRUCTOR
332}
333
334/*!
335 Creation d'une classe de fit pour le `GeneralXi2 f'.
336 L'emploi de cette methode n'est pas conseillee car elle
337 calcule automatiquement la derivee 2sd du Xi2 par rapport
338 aux parametres, ce qui entraine un manque de robustesse
339 et qui ne garanti pas que la matrice de covariance soit
340 definie positive (il est possible de surecrire
341 la methode virtuelle Derivee2 pour palier ce probleme).
342*/
343GeneralFit::GeneralFit(GeneralXi2* f)
344 : mNVar (0),
345 mNPar (f->NPar()),
346 mFunction (NULL),
347 mFuncXi2 (f),
348
349 Param (f->NPar()),
350 errParam (f->NPar()),
351 stepParam (f->NPar()),
352 minParam (f->NPar()),
353 maxParam (f->NPar()),
354 minStepDeriv (f->NPar()),
355 Eps (f->NPar()),
356
357 ATGA (f->NPar(), f->NPar()),
358 BETA (f->NPar()),
359 ATGA_Try (f->NPar(), f->NPar()),
360 BETA_Try (f->NPar()),
361 C (f->NPar()),
362 D (f->NPar())
363{
364 ASSERT( mNPar>0 );
365 ASSERT( mNPar < 1000000 );
366
367 TRY {
368 General_Init();
369 } CATCHALL {
370 THROW_SAME;
371 } ENDTRY
372
373 END_CONSTRUCTOR
374}
375
376//
377void GeneralFit::General_Init(void)
378// Initialisation des diverses variables
379{
380 mNtry = 0;
381 mNParFree = mNPar;
382 mNParBound = 0;
383
384 mData = NULL;
385
386 fixParam = NULL;
387 boundParam = NULL;
388 nameParam = NULL;
389
390 Lambda_Fac = 10.;
391 stopChi2 = 0.01;
392 maxStep = 100;
393 nStopMx = 3;
394 stopChi2SMx = stopChi2;
395 nStopLent = 0;
396 debugLevel = 0;
397 FileStep = NULL;
398
399 Chi2 = 0.;
400 mNddl = -1;
401 nStep = 0;
402 nStop = 0;
403 nStopL = 0;
404 Lambda = 0.001;
405
406 GetIntEnv("PDEBUG_GENERALFIT",debugLevel);
407
408 TRY {
409 fixParam = new unsigned short int[mNPar];
410 boundParam = new unsigned short int[mNPar];
411 nameParam = new string[mNPar];
412 } CATCHALL {
413 cout<<"GeneralFit::GeneralFit Impossible d'allouer l'espace"<<endl;
414 THROW_SAME;
415 } ENDTRY
416
417 Param = (double) 0.;
418 errParam = (double) 0.;
419 stepParam = (double) 1.;
420 minParam = (double) 1.;
421 maxParam = (double) -1.;
422 minStepDeriv = (double) 0.;
423 Eps = (double) EPS_FIT_MIN;
424 char str[8];
425 for(int i=0;i<mNPar;i++) {
426 sprintf(str,"P%d",i);
427 fixParam[i] = 0;
428 boundParam[i] = 0;
429 nameParam[i] = str;
430 }
431}
432
433GeneralFit::~GeneralFit()
434{
435 delete[] fixParam;
436 delete[] boundParam;
437 delete[] nameParam;
438 if(FileStep!=NULL) fclose(FileStep);
439}
440
441//////////////////////////////////////////////////////////////////////
442/*!
443 Pour ecrire les iterations dans le fichier filename
444*/
445void GeneralFit::WriteStep(char *filename)
446{
447
448#if defined(__DECCXX) || defined(__KCC__) || defined(__aCC__)
449if(filename==NULL) filename = const_cast<char *>("generalfit.iter");
450#else
451if(filename==NULL) filename = "generalfit.iter";
452#endif
453FileStep = fopen(filename,"w");
454if(FileStep==NULL) THROW(nullPtrErr);
455}
456
457/*!
458 Niveau de debug
459 (voir aussi la variable d'environnement PDEBUG_GENERALFIT).
460*/
461void GeneralFit::SetDebug(int level)
462{
463 debugLevel = ( level < 0 ) ? 0: level;
464 if(debugLevel>0) cout<<"SetDebug_level "<<debugLevel<<endl;
465}
466
467/*!
468 Nombre maximum d'iterations permis.
469*/
470void GeneralFit::SetMaxStep(int n)
471{
472 maxStep = ( n <= 1 ) ? 100: n;
473 if(debugLevel>0) cout<<"SetMaxStep "<<maxStep<<endl;
474}
475
476/*!
477 Facteur de multiplication/division de Lambda selon
478 que le Chi2 a augmente ou diminue.
479*/
480void GeneralFit::SetLambda_Fac(double fac)
481{
482 Lambda_Fac = (fac>1.) ? fac : 10.;
483}
484
485/*!
486 Critere de convergence sur le Chi2.
487*/
488void GeneralFit::SetStopChi2(double s)
489{
490 stopChi2 = ( s <= 0. ) ? 0.01: s;
491 if(debugLevel>0) cout<<"SetStopChi2 "<<stopChi2<<endl;
492}
493
494/*!
495 Precision des calculs (cf \ref GeneralFit_Fit "descriptif general").
496*/
497void GeneralFit::SetEps(double ep)
498{
499 ep = (ep<=0.) ? EPS_FIT_MIN: ep;
500 if(debugLevel>0) cout<<"SetEps "<<ep<<endl;
501 for(int i=0;i<mNPar;i++) SetEps(i,ep);
502}
503
504/*!
505 Precision des calculs pour le parametre n.
506*/
507void GeneralFit::SetEps(int n,double ep)
508{
509 ASSERT(n>=0 && n<mNPar);
510 Eps(n) = (ep<=0.) ? EPS_FIT_MIN: ep;
511 if(debugLevel>0) cout<<"SetEps("<<n<<") = "<<Eps(n)<<endl;
512}
513
514/*!
515 Critere de convergence sur le nombre de stop en chi2
516 dans le cas ou le chi2 augmente de moins de stopchi2
517 (cf \ref GeneralFit_Fit "descriptif general").
518
519 Si nstopmx<=0, alors ce critere de convergence n'est pas applique.
520
521 Si stopchi2<=0, alors la valeur generale mise par SetStopChi2()
522 est utilisee.
523*/
524void GeneralFit::SetStopMx(int nstopmx,double stopchi2)
525{
526 nStopMx = (nstopmx>0) ? nstopmx : 0;
527 stopChi2SMx = (stopchi2>0.) ? stopchi2 : stopChi2;
528 if(debugLevel>0) cout<<"SetStopMx: nStopMx="<<nStopMx
529 <<" stopChi2SMx="<<stopChi2SMx<<endl;
530}
531
532/*!
533 Critere de convergence sur le nombre de stop en chi2
534 dans le cas ou le chi2 diminue (cf \ref GeneralFit_Fit "descriptif general").
535
536 Si nstopl<=0, alors ce critere de convergence n'est pas applique.
537*/
538void GeneralFit::SetStopLent(int nstoplent)
539{
540 nStopLent = (nstoplent>0) ? nstoplent : 0;
541 if(debugLevel>0) cout<<"SetStopLent "<<nStopLent<<endl;
542}
543
544//////////////////////////////////////////////////////////////////////
545/*!
546 Pour changer la fonction a fitter en cours de route
547 (On ne peut passer d'un fit sur une GeneralFunction
548 a un fit sur un GeneralXi2 sans recreer la classe).
549*/
550void GeneralFit::SetFunction(GeneralFunction* f)
551{
552 ASSERT( mFuncXi2 == NULL );
553 ASSERT( f != NULL );
554 ASSERT( f->NVar() == mNVar );
555 ASSERT( f->NPar() == mNPar );
556 mFunction = f;
557 if(debugLevel>0) cout<<"SetFunction "<<mFunction<<endl;
558}
559
560/*!
561 Pour changer le Xi2 a fitter en cours de route
562 (On ne peut passer d'un fit sur une GeneralFunction
563 a un fit sur un GeneralXi2 sans recreer la classe).
564*/
565void GeneralFit::SetFuncXi2(GeneralXi2* f)
566{
567 ASSERT( mFunction == NULL );
568 ASSERT( f != NULL );
569 ASSERT( f->NPar() == mNPar );
570 mFuncXi2 = f;
571 if(debugLevel>0) cout<<"SetFuncXi2 "<<mFuncXi2<<endl;
572}
573
574//////////////////////////////////////////////////////////////////////
575/*!
576 Pour connecter une structure de donnees.
577*/
578void GeneralFit::SetData(GeneralFitData* data)
579{
580 ASSERT( data->NVar()==mNVar );
581 mData = data;
582 mNddl = mData->NDataGood() - mNParFree;
583 if(debugLevel>0)
584 cout<<"SetData "<<mData<<" data pour "<<mNddl<<" ddl"<<endl;
585}
586
587//////////////////////////////////////////////////////////////////////
588/*!
589 Definition du parametre "n" a fitter.
590*/
591void GeneralFit::SetParam(int n,double value,double step
592 ,double min,double max)
593{
594 ASSERT(n>=0 && n<mNPar);
595
596 Param(n) = value;
597 if(step>0.) {
598 if( fixParam[n] ) { fixParam[n]=0; mNParFree++;}
599 } else {
600 if( ! fixParam[n] ) { fixParam[n]=1; mNParFree--;}
601 }
602 stepParam(n) = step;
603 minParam(n) = min;
604 maxParam(n) = max;
605 if(max>min) {
606 if( ! boundParam[n] ) {boundParam[n]=1; mNParBound++;}
607 } else {
608 if( boundParam[n] ) {boundParam[n]=0; mNParBound--;}
609 }
610
611 if(debugLevel) {cout<<"Set_"; PrintParm(n);}
612}
613
614/*!
615 Definition du parametre "n" a fitter
616*/
617void GeneralFit::SetParam(int n, string const& name
618 ,double value,double step,double min,double max)
619{
620 ASSERT(n>=0 && n<mNPar);
621 SetParam(n,value,step,min,max);
622 nameParam[n] = name;
623 if(debugLevel) {cout<<"Set_Param "; PrintParm(n);}
624}
625
626/*!
627 Definition du parametre "n" a fitter
628*/
629void GeneralFit::SetParam(int n,double value)
630{
631 ASSERT(n>=0 && n<mNPar);
632 Param(n) = value;
633 if(debugLevel) {cout<<"Set_Param "; PrintParm(n);}
634}
635
636//////////////////////////////////////////////////////////////////////
637/*!
638 Definition du pas de depart du parametre "n"
639 Si negatif ou nul, parametre fixe.
640*/
641void GeneralFit::SetStep(int n,double step)
642{
643 ASSERT(n>=0 && n<mNPar);
644 if(step>0.) {
645 if( fixParam[n] ) { fixParam[n]=0; mNParFree++;}
646 } else {
647 if( ! fixParam[n] ) { fixParam[n]=1; mNParFree--;}
648 }
649 stepParam(n) = step;
650 if(debugLevel) {cout<<"Set_Step"; PrintParm(n);}
651}
652
653/*!
654 Definition du pas minimum `val' pour le parametre `i'
655 pouvant etre utilise dans le calcul automatique des derivees
656 (soit de la fonction, soit du Xi2 selon les parametres du fit).
657 Si nul pas de limite, si negatif alors `EPS(i)' (cf SetEps).
658 Inutile dans le cas ou les derivees sont donnees
659 par l'utilisateur.
660*/
661void GeneralFit::SetMinStepDeriv(int i,double val)
662{
663 ASSERT(i>=0 && i<mNPar);
664 if(val<0.) minStepDeriv(i) = Eps(i);
665 else minStepDeriv(i) = val;
666 if(debugLevel>0) cout<<"SetMinStepDeriv("<<i<<") = "<<minStepDeriv(i)<<endl;
667}
668
669/*!
670 Definition du pas minimum `val' pour tout les parametres
671 (voir description SetMinStepDeriv ci-dessus).
672*/
673void GeneralFit::SetMinStepDeriv(double val)
674{
675 if(debugLevel>0) cout<<"SetMinStepDeriv "<<val<<endl;
676 for(int i=0;i<mNPar;i++) SetMinStepDeriv(i,val);
677}
678
679//////////////////////////////////////////////////////////////////////
680/*!
681 Definition des bornes du parametre "n"
682 Si max<=min, parametre non-borne.
683*/
684void GeneralFit::SetBound(int n, double min, double max)
685{
686 ASSERT(n>=0 && n<mNPar && max>min);
687
688 minParam(n) = min;
689 maxParam(n) = max;
690 if( ! boundParam[n] ) {
691 boundParam[n] = 1;
692 mNParBound++;
693 if(debugLevel>0)
694 cout<<"SetBound "<<n<<" min="<<min<<" max="<<max
695 <<" (Nbound="<<mNParBound<<")"<<endl;
696 }
697}
698
699/*!
700 Pour re-borner le parametre "n" aux bornes par defaut
701*/
702void GeneralFit::SetBound(int n)
703{
704 ASSERT(n>=0 && n<mNPar && maxParam(n)>minParam(n));
705 SetBound(n,minParam(n),maxParam(n));
706}
707
708/*!
709 Pour ne plus borner le parametre "n"
710*/
711void GeneralFit::SetUnBound(int n)
712{
713 ASSERT(n>=0 && n<mNPar);
714
715 if( boundParam[n] ) {
716 boundParam[n] = 0;
717 mNParBound--;
718 if(debugLevel>0) cout<<" SetUnBound "<<n
719 <<" (Nbound="<<mNParBound<<")"<<endl;
720 }
721}
722
723/*!
724 Pour ne plus borner tous les parametres
725*/
726void GeneralFit::SetUnBound()
727{
728 for(int i=0;i<mNPar;i++) SetUnBound(i);
729}
730
731//////////////////////////////////////////////////////////////////////
732/*!
733 Pour fixer le parametre "n" a la valeur "v"
734*/
735void GeneralFit::SetFix(int n,double v)
736{
737 ASSERT(n>=0 && n<mNPar);
738
739 Param(n) = v;
740 if( ! fixParam[n] ) {
741 fixParam[n] = 1;
742 mNParFree--;
743 }
744 if(debugLevel>0) cout<<" SetFix "<<n
745 <<" v="<<v
746 <<" (Nfree="<<mNParFree
747 <<")"<<endl;
748}
749
750/*!
751 Pour fixer le parametre "n" a la valeur par defaut
752*/
753void GeneralFit::SetFix(int n)
754{
755 ASSERT(n>=0 && n<mNPar);
756 SetFix(n,Param(n));
757}
758
759/*!
760 Pour liberer le parametre "n"
761*/
762void GeneralFit::SetFree(int n)
763{
764 ASSERT(n>=0 && n<mNPar);
765
766 if( fixParam[n] ) {
767 fixParam[n] = 0;
768 mNParFree++;
769 if(debugLevel>0) cout<<" SetFree "<<n
770 <<" Step "<<stepParam(n)
771 <<" (Nfree="<<mNParFree<<")"<<endl;
772 if(stepParam(n)<=0.)
773 cout<<"ATTENTION SetFree["<<n<<"] avec step<=0 "
774 <<stepParam(n)<<endl;
775 }
776}
777
778/*!
779 Pour liberer tous les parametres
780*/
781void GeneralFit::SetFree()
782{
783 for(int i=0;i<mNPar;i++) SetFree(i);
784}
785
786//////////////////////////////////////////////////////////////////////
787/*!
788 Retourne la valeur du parametre "n"
789*/
790double GeneralFit::GetParm(int n)
791{
792 ASSERT(n>=0 && n<mNPar);
793 return Param(n);
794}
795
796/*!
797 Retourne les valeurs des parametres dans un vecteur.
798*/
799TVector<r_8> GeneralFit::GetParm()
800{
801return Param;
802}
803
804/*!
805 Retourne la valeur de l'erreur du parametre "n"
806*/
807double GeneralFit::GetParmErr(int n)
808{
809 ASSERT(n>=0 && n<mNPar);
810 return errParam(n);
811}
812
813/*!
814 Retourne la covariance pour les parametre `i' et `j'
815*/
816double GeneralFit::GetCoVar(int i,int j)
817{
818 ASSERT(i>=0 && i<mNPar && j>=0 && j<mNPar);
819 return ATGA(i,j);
820}
821
822//////////////////////////////////////////////////////////////////////
823/*!
824 Retourne la valeur du pas du parametre "n"
825*/
826double GeneralFit::GetStep(int n)
827{
828 ASSERT(n>=0 && n<mNPar);
829 return stepParam(n);
830}
831
832/*!
833 Retourne la valeur de la borne superieure du parametre "n"
834*/
835double GeneralFit::GetMax(int n)
836{
837 ASSERT(n>=0 && n<mNPar);
838 return maxParam(n);
839}
840
841/*!
842 Retourne la valeur de la borne inferieure du parametre "n"
843*/
844double GeneralFit::GetMin(int n)
845{
846 ASSERT(n>=0 && n<mNPar);
847 return minParam(n);
848}
849
850//////////////////////////////////////////////////////////////////////
851/*!
852 Impression du status du fit
853*/
854void GeneralFit::PrintStatus()
855{
856 cout<<"GeneralFit::PrintStatus"
857 <<" mData="<<mData
858 <<" mFunction="<<mFunction
859 <<" mFuncXi2="<<mFuncXi2
860 <<endl;
861 cout<<" mNVar="<<mNVar
862 <<" mNPar="<<mNPar
863 <<" mNParFree="<<mNParFree
864 <<" mNParBound="<<mNParBound
865 <<endl;
866 cout<<" Lambda_Fac="<<Lambda_Fac
867 <<" stopChi2="<<stopChi2
868 <<" maxStep="<<maxStep
869 <<" nStopMx="<<nStopMx<<" stopChi2SMx="<<stopChi2SMx
870 <<" nStopLent="<<nStopLent
871 <<" debugLevel="<<debugLevel
872 <<endl;
873 PrintParm();
874}
875
876/*!
877 Impression des resultats du fit
878*/
879void GeneralFit::PrintFit()
880{
881 cout<<"PrintFit: Chi2="<<Chi2
882 <<" Lambda="<<Lambda
883 <<" nStep="<<nStep
884 <<" nStop="<<nStop
885 <<" nStopL="<<nStopL
886 <<" nDDL="<<mNddl
887 <<endl;
888 PrintParm();
889}
890
891/*!
892 Impression des informations relatives au parametre "n"
893*/
894void GeneralFit::PrintParm(int n)
895{
896 ASSERT(n>=0 && n<mNPar);
897
898 cout<<"Par["<<n<<"] "<<nameParam[n]
899 <<" F"<<fixParam[n]
900 <<" B"<<boundParam[n]
901 <<" : "<<Param(n)
902 <<" +/- "<<errParam(n)
903 <<" : "<<stepParam(n)
904 <<" "<<minParam(n)
905 <<" "<<maxParam(n)
906 <<" : "<<Eps(n)
907 <<" "<<minStepDeriv(n)
908 <<endl;
909}
910
911/*!
912 Impression des informations relatives a tous les parametres
913*/
914void GeneralFit::PrintParm()
915{
916 cout<<"*** Parametres : fix bnd : par err : step min max : eps dmin\n";
917 for (int i=0; i<mNPar; i++) PrintParm(i);
918 cout<<endl;
919}
920
921//////////////////////////////////////////////////////////////////////
922/*!
923 Methode de fit.
924 \anchor GeneralFit_Fit
925 \verbatim
926 Fonction de fit de la fonction f(x,y,z,...:p1,p2,...,pn)
927 sur les donnees x[i],y[i],z[i],...,F[i],ErrF[i]
928 - Methode: fit des moindres carres dans le cas non lineaire
929 - Reference: Statistical and Computational Methods in Data Analysis
930 Siegmund Brandt, North-Holland 1970 p 204-206.
931 Introduction des limites pour la variation des parametres (cmv).
932 Increment des parametres selon la methode de Levenberg-Marquardt
933 (Numerical Recipes in C, chap 15 Modeling of Data, Nonlinear Models,
934 Levenberg-Marquardt Method p683)
935 - Gestion des parametres bornes:
936 si p est un parametre borne entre pmin et pmax, le parametre fitte est q
937 tel que q = tang((p-C)/D) .... p = C + D*atan(q)
938 ou C = (pmin+pmax)/2. et D = (pmax-pmin)/Pi
939 On a dq = (1+q**2)/D * dp .... dp = D/(1+q**2) * dq
940 et dF/dq = dF/dp * dp/dq = D/(1+q**2) * dF/dp
941 dF/dp = dF/dq * dq/dp = (1+q**2)/D * dF/dp
942 ^ q
943 | | *| "tang()"
944 | | *|
945 | | *|
946 | | * |
947 | | * |
948 | | * |
949 | | * |
950 Pmin| C| * |Pmax
951 --------------|---------------*---------------|--------------> p
952 -Pi/2| * |0 |Pi/2
953 | * | |
954 | * | |
955 | * | |
956 | * | |
957 |* | |
958 |* | |
959 |* | |
960 <------------------- D --------->
961
962 - Criteres de convergence, arrets standards:
963 - SOIT: le Chi2 est descendu de moins de stopChi2
964 entre l'iteration n et n+1
965 (stopChi2 est change par SetStopChi2)
966 - SOIT: 1. le chi2 est remonte de moins de stopChi2SMx et
967 2. les parametres libres ont varie de moins de Eps(i)
968 pendant les nStopmx dernieres iterations
969 Si nStopmx<=0, alors ce critere n'est pas applique (def=3).
970 (nStopmx,stopChi2SMx sont changes par SetStopMx, Eps par SetEps)
971
972 - Criteres de convergence, arrets par non-convergence:
973 - plus de "maxStep" iterations.
974
975 - Criteres de convergence, arrets speciaux:
976 - Si l'utilisateur a demande explicitement la methode d'arret
977 "SetStopLent()", arret si :
978 1. le Chi2 est descendu et
979 2. les parametres libres ont varies de moins de Eps
980 pendant les nStopLent dernieres iterations.
981 (nStopLent est change par SetStopLent, Eps par SetEps)
982
983 - Remarques diverses:
984 Les points avec erreurs <=0 ne sont pas utilises dans le fit.
985 Les bornes des parametres ne peuvent etre atteintes
986 - entrees:
987 la fonction est definie par une classe GeneralFunction
988 les donnees sont passees par une classe GeneralFitData
989 le nombre de parametres et le nombre de variables doivent etre
990 coherents entre GeneralFunction GeneralFitData GeneralFit
991 - Return:
992 la function elle meme retourne le nombre d'iterations du fit si succes
993 -1 : si le nombre de degre de liberte est <0
994 -10 : si l'inversion de la matrice des erreurs n'a pas ete possible
995 -11 : si un element diagonal de la matrice des covariances est <=0
996 -20 : si le fit n'a pas converge (nstep>nNstepMX)
997 -100-N : si le parametre "N" est initialise hors limites
998 -200-N : si le parametre "N" atteint sa limite inferieure
999 -300-N : si le parametre "N" atteint sa limite superieure
1000 \endverbatim
1001*/
1002int GeneralFit::Fit()
1003{
1004 volatile double oldChi2;
1005 TMatrix<r_8> COVAR(mNPar,mNPar);
1006 TVector<r_8> DA(mNPar);
1007 TVector<r_8> dparam(mNPar);
1008 TVector<r_8> paramTry(mNPar);
1009 TVector<r_8> param_tr(mNPar);
1010 TVector<r_8> paramTry_tr(mNPar);
1011 TVector<r_8> step_tr(mNPar);
1012 nStop = nStopL = nStep = 0;
1013 Chi2 = oldChi2 = 0.;
1014 Lambda = 0.001;
1015 mNddl = mData->NDataGood() - mNParFree;
1016 if(mNddl<0) return -1;
1017 mNtry++;
1018
1019 if(debugLevel>= 2)
1020 cout<<"\n********* DEBUT GENERALFIT.FIT() **************"<<endl;
1021
1022 // set matrices C,D dans le cas de parametres bornes
1023 if(mNParBound>0) Set_Bound_C_D();
1024
1025 if(debugLevel>= 2) PrintStatus();
1026
1027 // check de la coherence des operations et assignations
1028 CheckSanity();
1029
1030 // Pour les parametres bornes on verifie
1031 // qu'ils sont initialises dans leurs limites
1032 {for(int i=0;i<mNPar;i++) {
1033 if( !boundParam[i] || fixParam[i] ) continue;
1034 if( minParam(i)<Param(i) && Param(i)<maxParam(i) ) continue;
1035 /* if(debugLevel>= 1) */
1036 cout<<"Parametre "<<i<<" initialise hors limites "
1037 <<minParam(i)<<" < "<<Param(i)
1038 <<" < "<<maxParam(i)<<endl;
1039 return(-100-i);
1040 }}
1041
1042 // premier essai d'initialisation
1043 param_tr = p_vers_tr(Param);
1044 dparam = stepParam / 2.;
1045 put_in_limits_for_deriv(Param,dparam);
1046 if(mFunction!=NULL) mFunction->SetDeltaParm(dparam.Data());
1047 else if(mFuncXi2!=NULL) mFuncXi2->SetDeltaParm(dparam.Data());
1048 step_tr = dp_vers_dtr(stepParam,param_tr);
1049
1050 if(debugLevel>= 2) {
1051 cout<<"ESSAI numero 1: Param:"<<endl;
1052 cout<<Param;
1053 cout<<"param_tr:"<<endl;
1054 cout<<param_tr;
1055 cout<<"step_tr:"<<endl;
1056 cout<<step_tr;
1057 }
1058 if(mFunction!=NULL) TryFunc(Param,param_tr);
1059 else if(mFuncXi2!=NULL) TryXi2(Param,param_tr);
1060 ATGA = ATGA_Try;
1061 BETA = BETA_Try;
1062 oldChi2 = Chi2;
1063
1064 // Iterations
1065 while (1) {
1066 nStep++;
1067
1068 // un nouvel essai (si Lambda!=0)
1069 {for(int i=0; i<mNPar; i++)
1070 if(! fixParam[i] ) ATGA(i,i) *= 1 + Lambda;
1071 else ATGA(i,i) = 1.;}
1072
1073 // Calcul de la matrice des covariances
1074#ifdef __mac__
1075 COVAR = SimpleMatrixOperation<r_8>::Inverse(ATGA); /* $CHECK$ Reza 10/3/2000 */
1076#else
1077 TRY {
1078 COVAR = SimpleMatrixOperation<r_8>::Inverse(ATGA); /* $CHECK$ Reza 10/3/2000 */
1079 } CATCHALL {
1080 if(debugLevel>0) {
1081 cout<<"Pb inversion matrice ATGA:"<<endl;
1082 cout<<ATGA;
1083 }
1084 return(-10);
1085 } ENDTRY
1086#endif
1087
1088 if (debugLevel >= 3) {
1089 cout<<"Matrice (tA G A)^-1 = \n";
1090 cout<<COVAR;
1091 }
1092
1093 // calculs des deplacements a effectuer
1094 DA = COVAR * BETA;
1095 if (debugLevel >=2) {
1096 cout<<"Correction parametres DA : \n";
1097 cout<<DA;
1098 }
1099
1100
1101 //////////////////////////////////////////////////
1102 ////////////////// Arret du Fit //////////////////
1103 // si Lambda = 0, le fit a converge on s'arrete
1104 // ou bien on a trop d'iterations
1105 //////////////////////////////////////////////////
1106 if(Lambda == 0 || nStep > maxStep) {
1107 // trop d'iterations
1108 if(nStep>maxStep)
1109 cout<<"GeneralFit : pas de convergence"<<endl;
1110 // Probleme de matrice de covariance non-definie positive?
1111 bool bad_covar = false;
1112 {for(int i=0; i<mNPar; i++) {
1113 if( fixParam[i] ) errParam(i) = 0.;
1114 else {
1115 stepParam(i) = DA(i);
1116 if( COVAR(i,i)<=0. ) {
1117 if( debugLevel>0 )
1118 cout<<"Erreur: Par["<<i<<"]="<<param_tr(i)
1119 <<" ("<<Param(i)<<") COVAR()="<<COVAR(i,i)
1120 <<" step="<<DA(i)<<endl;
1121 errParam(i) = 0.;
1122 bad_covar = true;
1123 } else {
1124 errParam(i) = sqrt( COVAR(i,i) );
1125 }
1126 }
1127 }}
1128 // print de debug pour parametres bornes
1129 if(debugLevel>= 2) {
1130 cout<<"param_tr:"<<endl;
1131 cout<<param_tr;
1132 cout<<"stepParam_tr:"<<endl;
1133 cout<<stepParam;
1134 cout<<"errParam_tr:"<<endl;
1135 cout<<errParam;
1136 }
1137 // Calcul de la matrice des covariances
1138 {for(int i=0; i<mNPar; i++) {
1139 for(int j=0; j<mNPar; j++) {
1140 if( fixParam[i] || fixParam[j] ) {
1141 // Parametre fixe, on retourne l'identite
1142 if(i==j) ATGA(i,j) = 1.; else ATGA(i,j) = 0.;
1143 } else if( errParam(i)<=0. || errParam(j)<=0.) {
1144 // parametres avec mauvaise variance, on retourne 0
1145 ATGA(i,j) = 0;
1146 } else {
1147 // parametres OK
1148 ATGA(i,j) = COVAR(i,j)/(errParam(i)*errParam(j));
1149 }
1150 }
1151 }}
1152 if (debugLevel >= 1) {
1153 cout<<">>> Matrice des Covariances = \n";
1154 cout<<ATGA;
1155 }
1156 // Calcul du step et de l'erreur finale en tenant
1157 // compte des parametres bornes
1158 stepParam = dtr_vers_dp(stepParam,param_tr);
1159 errParam = dtr_vers_dp(errParam,param_tr);
1160 // Print si demande et code de retour.
1161 if (debugLevel>0 ) PrintFit();
1162 if(nStep>maxStep) return(-20);
1163 else if(bad_covar) return(-11);
1164 else return(nStep);
1165 }
1166 ////////////////////////////////////////////////////////
1167 ////////////////// Fin d'Arret du Fit //////////////////
1168 ////////////////////////////////////////////////////////
1169
1170 // Gestion des deplacements
1171 {for (int i=0; i<mNPar; i++) {
1172 if( fixParam[i] ) { DA(i) = 0; continue;}
1173 // le premier deplacement ne peut etre plus grand que stepParam
1174 if( nStep == 1 && fabs(DA(i)) > step_tr(i) ) {
1175 DA(i) = DA(i) < 0. ? -step_tr(i) : step_tr(i);
1176 if(debugLevel>1 ) cout<<"Excursion parametre "<<i
1177 <<" limitee a "<<DA(i)<<endl;
1178 }
1179 }}
1180 paramTry_tr = param_tr + DA;
1181 paramTry = tr_vers_p(paramTry_tr);
1182 dparam = dtr_vers_dp(DA,paramTry_tr);
1183 dparam /= 2.;
1184 put_in_limits_for_deriv(paramTry,dparam);
1185 {for(int i=0; i<mNPar; i++) {
1186 if( ! boundParam[i] ) continue;
1187 if(paramTry(i) <= minParam(i)) {
1188 if(debugLevel>0) cout<<"Parametre "<<i
1189 <<" limite au minimum"<<endl;
1190 Param(i) = minParam(i);
1191 return(-200-i);
1192 } else if (paramTry(i) >= maxParam(i)) {
1193 if(debugLevel>0) cout<<"Parametre "<<i
1194 <<" limite au maximum"<<endl;
1195 Param(i) = maxParam(i);
1196 return(-300-i);
1197 }
1198 }}
1199
1200 // Nouvel essai
1201 if(mFunction!=NULL) mFunction->SetDeltaParm(dparam.Data());
1202 else if(mFuncXi2!=NULL) mFuncXi2->SetDeltaParm(dparam.Data());
1203 if(debugLevel >= 2) {
1204 cout<<">>>>>>>>>>> ESSAI avec nouveaux parametres\n";
1205 cout<<"paramTry:\n";
1206 cout<<paramTry;
1207 cout<<"paramTry_tr:\n";
1208 cout<<paramTry_tr;
1209 cout<<"dparam:\n";
1210 cout<<dparam;
1211 }
1212 if(mFunction!=NULL) TryFunc(paramTry,paramTry_tr);
1213 else if(mFuncXi2!=NULL) TryXi2(paramTry,paramTry_tr);
1214
1215 if (debugLevel >= 2)
1216 cout<<"step "<<nStep<<" Chi2 : old="<<oldChi2
1217 <<" new="<<Chi2<<" d="<<Chi2-oldChi2<<endl;
1218 if(FileStep) write_in_step(Chi2,paramTry);
1219
1220 // *************************************************************
1221 // ****************** quelle strategie sur Lambda ???? *********
1222 // *************************************************************
1223 if (Chi2 < oldChi2) {
1224 // ****************** le Chi2 est descendu ******************
1225 nStop = 0;
1226 if(nStopLent>0) {
1227 // Arret special demande, comment se comporte les parametres?
1228 int k=0;
1229 for (int i=0; i<mNPar; i++) if( (!fixParam[i]) &&
1230 (fabs(param_tr(i)-paramTry_tr(i))<Eps(i))) k++;
1231 if (k==mNParFree) nStopL++; // Tous les parametres ont peu varies
1232 else nStopL=0;
1233 if (debugLevel>=2) cout<<k<<" parametres sur "<<mNParFree
1234 <<" ont peu varies, nStopL="<<nStopL<<endl;
1235 } else nStopL = 0;
1236 // Preparation des parametres pour iteration suivante
1237 ATGA = ATGA_Try;
1238 BETA = BETA_Try;
1239 param_tr = paramTry_tr;
1240 Param = paramTry;
1241 Lambda *= 1./Lambda_Fac;
1242 // Arret ?
1243 if (oldChi2-Chi2<stopChi2) {
1244 // arret normal, convergence
1245 Lambda = 0;
1246 if (debugLevel >= 2)
1247 cout<<"Arret>> demande car Chi2 decroit et oldChi2-Chi2= "
1248 <<oldChi2-Chi2<<"<"<<stopChi2<<endl;
1249 } else if (nStopLent>0 && nStopL >= nStopLent) {
1250 // arret demande par SetStopLent, variation lente des parametres
1251 Lambda = 0.;
1252 if (debugLevel >= 2)
1253 cout<<"Arret>> demande car Chi2 decroit et nStop(lent)= "
1254 <<nStopL<<">="<<nStopLent<<endl;
1255 }
1256 oldChi2 = Chi2;
1257 if (debugLevel >= 2) cout<<"Succes essai: Lambda divided by "
1258 <<Lambda_Fac<<" -> "<<Lambda<<endl;
1259 } else {
1260 // ****************** le Chi2 est remonte ******************
1261 nStopL = 0;
1262 if(nStopMx>0 && Chi2-oldChi2<stopChi2SMx) {
1263 // Il est remonte tres peu, comment se comporte les parametres?
1264 int k=0;
1265 for (int i=0; i<mNPar; i++) if( (!fixParam[i]) &&
1266 (fabs(param_tr(i)-paramTry_tr(i))<Eps(i))) k++;
1267 if (k==mNParFree) nStop++; // Tous les parametres ont peu varies
1268 else nStop=0;
1269 if (debugLevel>=2) cout<<k<<" parametres sur "<<mNParFree
1270 <<" ont peu varies, nStop="<<nStop<<endl;
1271 } else nStop = 0;
1272 // Preparation des parametres pour iteration suivante
1273 Lambda *= Lambda_Fac;
1274 // Arret ?
1275 if (nStopMx>0 && nStop>=nStopMx) {
1276 // arret normal, convergence car ci2 varie peu et parametres aussi
1277 Lambda = 0.;
1278 if (debugLevel >= 2)
1279 cout<<"Arret>> demande car Chi2 croit et nstop= "
1280 <<nStop<<">="<<nStopMx<<endl;
1281 }
1282 Chi2 = oldChi2;
1283 if (debugLevel >= 2)
1284 cout<<"Echec essai: Lambda multiplied by "<<Lambda_Fac
1285 <<" -> "<<Lambda<<" nStop="<<nStop<<endl;
1286 }
1287
1288 } // fin des iterations
1289}
1290
1291//////////////////////////////////////////////////////////////////////
1292/*!
1293 Recalcul du Chi2 a partir des parametres courants (`par==NULL')
1294 ou a partir du tableau de parametres `par'.
1295 Retourne le chi2 et le nombre de degres de liberte.
1296 Si nddl<0 probleme.
1297*/
1298double GeneralFit::ReCalChi2(int& nddl, double *par)
1299{
1300double c2 = -1.;
1301if(par==NULL) par = Param.Data();
1302if( mData->NData() <= 0 ) {nddl = -100; return 0.;}
1303
1304if( mFunction != NULL ) {
1305
1306 double e,result;
1307
1308 nddl = 0; c2 = 0.;
1309 for(int k=0; k<mData->NData(); k++) {
1310 if (! mData->mOK[k]) continue;
1311 e = mData->mErr[k];
1312 result = mFunction->Value(&mData->mXP[mNVar*k],par);
1313 c2 += (mData->mF[k]-result)*(mData->mF[k]-result)/(e*e);
1314 nddl++;
1315 }
1316 nddl -= mNParFree;
1317
1318 return c2;
1319
1320} else if( mFuncXi2 != NULL ) {
1321
1322 c2 = mFuncXi2->Value(*mData,par,nddl);
1323 nddl -= mNParFree;
1324 return c2;
1325
1326} else {
1327
1328 cout<<"GeneralFit::ReCalChi2_Erreur: mFunction && mFuncXi2 == NULL"<<endl;
1329 nddl = -1;
1330 return c2;
1331}
1332
1333}
1334
1335//////////////////////////////////////////////////////////////////////
1336/*!
1337 Retourne une structure ``GeneralFitData'' contenant
1338 les residus du fit (val-func) pour les points du fit.
1339 Si ``clean'' est ``true''
1340 seules les donnees valides de ``data'' sont copiees.
1341 Si ``clean'' est ``false'' (defaut) toutes les donnees
1342 sont copiees et la taille totale de ``data'' est allouee
1343 meme si elle est plus grande que la taille des donnees stoquees.
1344*/
1345GeneralFitData GeneralFit::DataResidus(bool clean)
1346{
1347if(!mData || !mFunction)
1348 throw(NullPtrError("GeneralFit::DataResidus: NULL pointer\n"));
1349GeneralFitData datres(*mData,clean);
1350for(int k=0; k<mData->NData(); k++)
1351 datres.mF[k] -= mFunction->Value(&datres.mXP[mNVar*k],Param.Data());
1352return datres;
1353}
1354
1355//////////////////////////////////////////////////////////////////////
1356/*!
1357 Retourne une structure ``GeneralFitData'' contenant
1358 les valeurs de la fonction fittee pour les points du fit.
1359 (voir commentaires pour ``clean'' dans ``DataResidus'')
1360*/
1361GeneralFitData GeneralFit::DataFunction(bool clean)
1362{
1363if(!mData || !mFunction)
1364 throw(NullPtrError("GeneralFit::DataFunction: NULL pointer\n"));
1365GeneralFitData datres(*mData,clean);
1366for(int k=0; k<mData->NData(); k++)
1367 datres.mF[k] = mFunction->Value(&datres.mXP[mNVar*k],Param.Data());
1368return datres;
1369}
1370
1371//////////////////////////////////////////////////////////////////////
1372/*!
1373 Imprime le commentaire lie a l'erreur rc retournee par Fit()
1374 (voir le commentaire de la methode `Fit()')
1375*/
1376void GeneralFit::PrintFitErr(int rc)
1377{
1378int n;
1379if(rc>0) return;
1380
1381if(rc==-1)
1382 cout<<"rc = "<<rc<<" : le nombre de degre de liberte est <0"<<endl;
1383
1384else if(rc==-10)
1385 cout<<"rc = "<<rc<<" : l'inversion de la matrice des erreurs n'a pas ete possible"<<endl;
1386
1387else if(rc==-11)
1388 cout<<"rc = "<<rc<<" : un element diagonal de la matrice des covariances est <=0"<<endl;
1389
1390else if(rc==-20)
1391 cout<<"rc = "<<rc<<" : le fit n'a pas converge (nstep>nNstepMX="<<maxStep<<")"<<endl;
1392
1393else if(rc>-200 && rc<=-100) {
1394 n = -100-rc;
1395 cout<<"rc = "<<rc<<" : le parametre "<<n<<" ("<<nameParam[n]
1396 <<") est initialise hors limites"<<endl;
1397}
1398
1399else if(rc>-300 && rc<=-200) {
1400 n = -200-rc;
1401 cout<<"rc = "<<rc<<" : le parametre "<<n<<" ("<<nameParam[n]
1402 <<") atteint sa limite inferieure"<<endl;
1403}
1404
1405else if(rc>-400 && rc<=-300) {
1406 n = -300-rc;
1407 cout<<"rc = "<<rc<<" : le parametre "<<n<<" ("<<nameParam[n]
1408 <<") atteint sa limite superieure"<<endl;
1409}
1410
1411else cout<<"rc = "<<rc<<" : type d'erreur inconnue"<<endl;
1412
1413}
1414
1415//////////////////////////////////////////////////////////////////////
1416// Fonctions privees
1417//////////////////////////////////////////////////////////////////////
1418
1419//////////////////////////////////////////////////////////////////////
1420void GeneralFit::write_in_step(double ci2,TVector<r_8>& par)
1421{
1422if(FileStep==NULL) return;
1423fprintf(FileStep,"%d %d %f",mNtry,nStep,ci2);
1424for(int i=0; i<mNPar; i++) fprintf(FileStep," %f",par(i));
1425fprintf(FileStep,"\n");
1426}
1427
1428//////////////////////////////////////////////////////////////////////
1429void GeneralFit::TryFunc(TVector<r_8>& par,TVector<r_8>& par_tr)
1430{
1431 BETA_Try = 0;
1432 ATGA_Try = 0;
1433 Chi2 = 0;
1434 TVector<r_8> deriv(mNPar);
1435 TVector<r_8> derivtr(mNPar);
1436 double result;
1437
1438 for(int k=0; k<mData->NData(); k++) {
1439 if (! mData->mOK[k]) continue;
1440 double e = mData->mErr[k];
1441 if(mNParBound==0)
1442 result = mFunction->Val_Der(&mData->mXP[mNVar*k]
1443 ,par.Data(),derivtr.Data());
1444 else {
1445 result = mFunction->Val_Der(&mData->mXP[mNVar*k]
1446 ,par.Data(),deriv.Data());
1447 dtr_vers_dp(deriv,par_tr,derivtr);
1448 }
1449 double Gkk = 1/(e*e);
1450 double Ck = mData->mF[k] - result;
1451 Chi2 += Ck*Ck*Gkk;
1452 for(int j=0; j<mNPar; j++) {
1453 if( fixParam[j] ) continue;
1454 for(int i=0; i<mNPar; i++)
1455 if(!fixParam[i]) ATGA_Try(i,j) += derivtr(i)*Gkk*derivtr(j);
1456 BETA_Try(j) += derivtr(j) * Gkk * Ck;
1457 }
1458 }
1459
1460 if (debugLevel >= 3) {
1461 cout<<"Try: matrice ( At * G * A )_Try\n";
1462 cout<<ATGA_Try;
1463 cout<<"Try: beta_Try:\n";
1464 cout<<BETA_Try;
1465 }
1466}
1467
1468//////////////////////////////////////////////////////////////////////
1469void GeneralFit::TryXi2(TVector<r_8>& par,TVector<r_8>& par_tr)
1470{
1471 double c, *parloc;
1472 BETA_Try = 0;
1473 ATGA_Try = 0;
1474 Chi2 = 0;
1475
1476 parloc = par.Data(); // He oui, encore ces ... de const*
1477 Chi2 = mFuncXi2->Value(*mData,parloc,mNddl);
1478 mNddl -= mNParFree;
1479
1480 // Calcul des derivees du Xi2 (vecteur du gradient)
1481 {for(int i=0;i<mNPar; i++) {
1482 if( fixParam[i] ) continue;
1483 c = c_dtr_vers_dp(i,par_tr(i));
1484 BETA_Try(i) = -0.5 * mFuncXi2->Derivee(*mData,i,parloc) * c;
1485 }}
1486
1487 // Calcul des derivees 2sd du Xi2 (matrice de courbure ou 0.5*Hessien)
1488 double c1,c2;
1489 {for(int i=0;i<mNPar; i++) {
1490 if( fixParam[i] ) continue;
1491 c1 = c_dtr_vers_dp(i,par_tr(i));
1492 for(int j=0;j<mNPar; j++) {
1493 if( fixParam[j] ) continue;
1494 c2 = c_dtr_vers_dp(j,par_tr(j));
1495 ATGA_Try(i,j) = 0.5 * mFuncXi2->Derivee2(*mData,i,j,parloc) *c1*c2;
1496 }
1497 }}
1498 // et on symetrise car d/di(dC2/dj) = d/dj(dC2/di) mathematiquement
1499 // mais malheureusement pas numeriquement.
1500 if( mNPar>1) {
1501 for(int i=0;i<mNPar-1; i++) {
1502 if( fixParam[i] ) continue;
1503 for(int j=i+1;j<mNPar; j++) {
1504 if( fixParam[j] ) continue;
1505 c1 = 0.5*(ATGA_Try(i,j) + ATGA_Try(j,i));
1506 ATGA_Try(i,j) = c1;
1507 ATGA_Try(j,i) = c1;
1508 }
1509 }
1510 }
1511
1512 if (debugLevel >= 3) {
1513 cout<<"Try: matrice ( At * G * A )_Try\n";
1514 cout<<ATGA_Try;
1515 cout<<"Try: beta_Try:\n";
1516 cout<<BETA_Try;
1517 }
1518}
1519
1520//////////////////////////////////////////////////////////////////////
1521void GeneralFit::CheckSanity()
1522{
1523 ASSERT( mData != NULL );
1524 ASSERT( mFunction != NULL || mFuncXi2 != NULL );
1525 if( mFunction != NULL ) {
1526 ASSERT( mFunction->NVar() == mNVar );
1527 ASSERT( mData->NVar() == mNVar );
1528 }
1529 ASSERT( mNParFree > 0 && mNParFree <= mNPar );
1530 ASSERT( mNParBound >= 0 && mNParBound <= mNPar );
1531 ASSERT( mNParFree <= mData->NDataGood() );
1532}
1533
1534//////////////////////////////////////////////////////////////////////
1535/*!
1536 \verbatim
1537 C = (min+max)/2
1538 D = (max-min)/Pi
1539 \endverbatim
1540*/
1541void GeneralFit::Set_Bound_C_D(int i)
1542{
1543 // ASSERT(i>=0 && i<mNPar);
1544 C(i) = D(i) = 0.;
1545 if( !boundParam[i] || fixParam[i] ) return;
1546 C(i) = (maxParam(i)+minParam(i))/2.;
1547 D(i) = (maxParam(i)-minParam(i))/M_PI;
1548}
1549
1550//////////////////////////////////////////////////////////////////////
1551void GeneralFit::Set_Bound_C_D()
1552{
1553 for(int i=0;i<mNPar;i++) Set_Bound_C_D(i);
1554 if(debugLevel>= 2) {
1555 cout<<"Set_Bound_C_D: C=\n";
1556 cout<<C;
1557 cout<<"Set_Bound_C_D: D=\n";
1558 cout<<D;
1559 }
1560}
1561
1562//////////////////////////////////////////////////////////////////////
1563/*!
1564 \verbatim
1565 tr = tan( (p-C)/D )
1566 \endverbatim
1567*/
1568double GeneralFit::p_vers_tr(int i,double p)
1569{
1570 // ASSERT(i>=0 && i<mNPar);
1571 double tr = p;
1572 if(boundParam[i]) tr = tan((p-C(i))/D(i));
1573 return(tr);
1574}
1575
1576//////////////////////////////////////////////////////////////////////
1577TVector<r_8> GeneralFit::p_vers_tr(TVector<r_8> const& p)
1578{
1579 TVector<r_8> tr(p);
1580 for(int i=0;i<mNPar;i++) {
1581 if( fixParam[i] || ! boundParam[i] ) continue;
1582 tr(i) = p_vers_tr(i,p(i));
1583 }
1584 return(tr);
1585}
1586
1587//////////////////////////////////////////////////////////////////////
1588void GeneralFit::p_vers_tr(TVector<r_8> const& p,TVector<r_8>& tr)
1589{
1590 for(int i=0;i<mNPar;i++) {
1591 if( fixParam[i] ) continue;
1592 if( ! boundParam[i] ) tr(i) = p(i);
1593 else tr(i) = tan((p(i)-C(i))/D(i));
1594 }
1595}
1596
1597//////////////////////////////////////////////////////////////////////
1598/*!
1599 \verbatim
1600 p = C+D*atan(tr)
1601 \endverbatim
1602*/
1603double GeneralFit::tr_vers_p(int i,double tr)
1604{
1605 // ASSERT(i>=0 && i<mNPar);
1606 double p = tr;
1607 if(boundParam[i]) p = C(i)+D(i)*atan(tr);
1608 return(p);
1609}
1610
1611//////////////////////////////////////////////////////////////////////
1612TVector<r_8> GeneralFit::tr_vers_p(TVector<r_8> const& tr)
1613{
1614 TVector<r_8> p(tr);
1615 for(int i=0;i<mNPar;i++) {
1616 if( fixParam[i] || ! boundParam[i] ) continue;
1617 p(i) = tr_vers_p(i,tr(i));
1618 }
1619 return(p);
1620}
1621
1622//////////////////////////////////////////////////////////////////////
1623void GeneralFit::tr_vers_p(TVector<r_8> const& tr,TVector<r_8>& p)
1624{
1625 for(int i=0;i<mNPar;i++) {
1626 if( fixParam[i] ) continue;
1627 if( ! boundParam[i] ) p(i) = tr(i);
1628 else p(i) = C(i)+D(i)*atan(tr(i));
1629 }
1630}
1631
1632//////////////////////////////////////////////////////////////////////
1633/*!
1634 \verbatim
1635 dtr = (1+tr**2)/D * dp = (1+tan( (p-C)/D )**2)/D * dp = coeff * dp
1636 attention: df/dp = (1+tr**2)/D * dF/dtr = coeff * dF/dtr
1637 \endverbatim
1638*/
1639double GeneralFit::c_dp_vers_dtr(int i,double tr)
1640{
1641 // ASSERT(i>=0 && i<mNPar);
1642 double coeff = 1.;
1643 if(boundParam[i]) coeff = (1.+tr*tr)/D(i);
1644 return(coeff);
1645}
1646
1647//////////////////////////////////////////////////////////////////////
1648TVector<r_8> GeneralFit::dp_vers_dtr(TVector<r_8> const& dp,TVector<r_8> const& tr)
1649{
1650 TVector<r_8> dtr(dp);
1651 for(int i=0;i<mNPar;i++) {
1652 if( fixParam[i] || ! boundParam[i] ) continue;
1653 dtr(i) *= c_dp_vers_dtr(i,tr(i));
1654 }
1655 return(dtr);
1656}
1657
1658//////////////////////////////////////////////////////////////////////
1659void GeneralFit::dp_vers_dtr(TVector<r_8> const& dp,TVector<r_8> const& tr,TVector<r_8>& dtr)
1660{
1661 for(int i=0;i<mNPar;i++) {
1662 if( fixParam[i] ) continue;
1663 if( ! boundParam[i] ) dtr(i) = dp(i);
1664 else dtr(i) = (1.+tr(i)*tr(i))/D(i) * dp(i);
1665 }
1666}
1667
1668//////////////////////////////////////////////////////////////////////
1669/*!
1670 \verbatim
1671 dp = D/(1+tr**2) * dtr = coeff * dtr
1672 attention: df/dtr = D/(1+tr**2) * dF/dp = coeff * dF/dp
1673 \endverbatim
1674*/
1675double GeneralFit::c_dtr_vers_dp(int i,double tr)
1676{
1677 // ASSERT(i>=0 && i<mNPar);
1678 double coeff = 1.;
1679 if(boundParam[i]) coeff = D(i)/(1.+tr*tr);
1680 return(coeff);
1681}
1682
1683//////////////////////////////////////////////////////////////////////
1684TVector<r_8> GeneralFit::dtr_vers_dp(TVector<r_8> const& dtr,TVector<r_8> const& tr)
1685{
1686 TVector<r_8> dp(dtr);
1687 for(int i=0;i<mNPar;i++) {
1688 if( fixParam[i] || ! boundParam[i] ) continue;
1689 dp(i) *= c_dtr_vers_dp(i,tr(i));
1690 }
1691 return(dp);
1692}
1693
1694//////////////////////////////////////////////////////////////////////
1695// inline fonction pour aller + vite dans le try()
1696//void GeneralFit::dtr_vers_dp(TVector<r_8> const& dtr,TVector<r_8> const& tr,TVector<r_8>& dp)
1697
1698//////////////////////////////////////////////////////////////////////
1699/*!
1700 \verbatim
1701 1-/ Redefinit dp pour qu'il soit superieur a minStepDeriv
1702 2-/ Redefinit dp pour que p+/-dp reste dans les limites (parametre borne)
1703 Si hors limites alors:
1704 p-dp <= min_p : dp = (p-min_p)*dist
1705 p+dp >= max_p : dp = (max_p-p)*dist
1706 \endverbatim
1707*/
1708int GeneralFit::put_in_limits_for_deriv(TVector<r_8> const& p,TVector<r_8>& dp,double dist)
1709{
1710 int nchanged = 0;
1711 bool changed;
1712 double dp_old;
1713
1714 for(int i=0;i<mNPar;i++) {
1715 if( fixParam[i] ) {dp(i)=0.; continue;} // Pas calcul derivee pour param fixe
1716
1717 if( fabs(dp(i))<minStepDeriv(i) ) {
1718 // On ne redefinit dp que si minStepDeriv>0.
1719 dp_old = dp(i);
1720 if(dp(i)>=0.) dp(i) = minStepDeriv(i); else dp(i) = -minStepDeriv(i);
1721 if(debugLevel>=2)
1722 cout<<"put_in_limits_for_deriv(range) dp["<<i<<"]=abs("<<dp_old
1723 <<") <"<<minStepDeriv(i)<<" changed to "<<dp(i)<<endl;
1724 }
1725
1726 if( !boundParam[i] ) continue;
1727
1728 changed = false;
1729 if( p(i)-dp(i)<=minParam(i) ) {
1730 dp_old = dp(i);
1731 dp(i) = dist*(p(i)-minParam(i));
1732 changed = true;
1733 if(debugLevel>=2)
1734 cout<<"put_in_limits_for_deriv(min) p["<<i<<"}="<<p(i)<<" >="
1735 <<minParam(i)<<" .. dp="<<dp_old<<" -> dp="<<dp(i)<<endl;
1736 }
1737
1738 if( p(i)+dp(i)>=maxParam(i) ) {
1739 dp_old = dp(i);
1740 dp(i) = dist*(maxParam(i)-p(i));
1741 changed = true;
1742 if(debugLevel>=2)
1743 cout<<"put_in_limits_for_deriv(max) p["<<i<<"]="<<p(i)<<" <="
1744 <<maxParam(i)<<" .. dp="<<dp_old<<" -> dp="<<dp(i)<<endl;
1745 }
1746
1747 if(changed) nchanged++;
1748 }
1749
1750 return nchanged;
1751}
1752
Note: See TracBrowser for help on using the repository browser.