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

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

intro du PPersist pour generalFitData
bug generalfit: pb du createur de Vector<r_8> qui share par defaut

cmv 13/7/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 if( mFunction != NULL ) {
581 ASSERT( data->NVar()==mNVar );
582 }
583 mData = data;
584 mNddl = mData->NDataGood() - mNParFree;
585 if(debugLevel>0)
586 cout<<"SetData "<<mData<<" data pour "<<mNddl<<" ddl"<<endl;
587}
588
589//////////////////////////////////////////////////////////////////////
590/*!
591 Definition du parametre "n" a fitter.
592*/
593void GeneralFit::SetParam(int n,double value,double step
594 ,double min,double max)
595{
596 ASSERT(n>=0 && n<mNPar);
597
598 Param(n) = value;
599 if(step>0.) {
600 if( fixParam[n] ) { fixParam[n]=0; mNParFree++;}
601 } else {
602 if( ! fixParam[n] ) { fixParam[n]=1; mNParFree--;}
603 }
604 stepParam(n) = step;
605 minParam(n) = min;
606 maxParam(n) = max;
607 if(max>min) {
608 if( ! boundParam[n] ) {boundParam[n]=1; mNParBound++;}
609 } else {
610 if( boundParam[n] ) {boundParam[n]=0; mNParBound--;}
611 }
612
613 if(debugLevel) {cout<<"Set_"; PrintParm(n);}
614}
615
616/*!
617 Definition du parametre "n" a fitter
618*/
619void GeneralFit::SetParam(int n, string const& name
620 ,double value,double step,double min,double max)
621{
622 ASSERT(n>=0 && n<mNPar);
623 SetParam(n,value,step,min,max);
624 nameParam[n] = name;
625 if(debugLevel) {cout<<"Set_Param "; PrintParm(n);}
626}
627
628/*!
629 Definition du parametre "n" a fitter
630*/
631void GeneralFit::SetParam(int n,double value)
632{
633 ASSERT(n>=0 && n<mNPar);
634 Param(n) = value;
635 if(debugLevel) {cout<<"Set_Param "; PrintParm(n);}
636}
637
638//////////////////////////////////////////////////////////////////////
639/*!
640 Definition du pas de depart du parametre "n"
641 Si negatif ou nul, parametre fixe.
642*/
643void GeneralFit::SetStep(int n,double step)
644{
645 ASSERT(n>=0 && n<mNPar);
646 if(step>0.) {
647 if( fixParam[n] ) { fixParam[n]=0; mNParFree++;}
648 } else {
649 if( ! fixParam[n] ) { fixParam[n]=1; mNParFree--;}
650 }
651 stepParam(n) = step;
652 if(debugLevel) {cout<<"Set_Step"; PrintParm(n);}
653}
654
655/*!
656 Definition du pas minimum `val' pour le parametre `i'
657 pouvant etre utilise dans le calcul automatique des derivees
658 (soit de la fonction, soit du Xi2 selon les parametres du fit).
659 Si nul pas de limite, si negatif alors `EPS(i)' (cf SetEps).
660 Inutile dans le cas ou les derivees sont donnees
661 par l'utilisateur.
662*/
663void GeneralFit::SetMinStepDeriv(int i,double val)
664{
665 ASSERT(i>=0 && i<mNPar);
666 if(val<0.) minStepDeriv(i) = Eps(i);
667 else minStepDeriv(i) = val;
668 if(debugLevel>0) cout<<"SetMinStepDeriv("<<i<<") = "<<minStepDeriv(i)<<endl;
669}
670
671/*!
672 Definition du pas minimum `val' pour tout les parametres
673 (voir description SetMinStepDeriv ci-dessus).
674*/
675void GeneralFit::SetMinStepDeriv(double val)
676{
677 if(debugLevel>0) cout<<"SetMinStepDeriv "<<val<<endl;
678 for(int i=0;i<mNPar;i++) SetMinStepDeriv(i,val);
679}
680
681//////////////////////////////////////////////////////////////////////
682/*!
683 Definition des bornes du parametre "n"
684 Si max<=min, parametre non-borne.
685*/
686void GeneralFit::SetBound(int n, double min, double max)
687{
688 ASSERT(n>=0 && n<mNPar && max>min);
689
690 minParam(n) = min;
691 maxParam(n) = max;
692 if( ! boundParam[n] ) {
693 boundParam[n] = 1;
694 mNParBound++;
695 if(debugLevel>0)
696 cout<<"SetBound "<<n<<" min="<<min<<" max="<<max
697 <<" (Nbound="<<mNParBound<<")"<<endl;
698 }
699}
700
701/*!
702 Pour re-borner le parametre "n" aux bornes par defaut
703*/
704void GeneralFit::SetBound(int n)
705{
706 ASSERT(n>=0 && n<mNPar && maxParam(n)>minParam(n));
707 SetBound(n,minParam(n),maxParam(n));
708}
709
710/*!
711 Pour ne plus borner le parametre "n"
712*/
713void GeneralFit::SetUnBound(int n)
714{
715 ASSERT(n>=0 && n<mNPar);
716
717 if( boundParam[n] ) {
718 boundParam[n] = 0;
719 mNParBound--;
720 if(debugLevel>0) cout<<" SetUnBound "<<n
721 <<" (Nbound="<<mNParBound<<")"<<endl;
722 }
723}
724
725/*!
726 Pour ne plus borner tous les parametres
727*/
728void GeneralFit::SetUnBound()
729{
730 for(int i=0;i<mNPar;i++) SetUnBound(i);
731}
732
733//////////////////////////////////////////////////////////////////////
734/*!
735 Pour fixer le parametre "n" a la valeur "v"
736*/
737void GeneralFit::SetFix(int n,double v)
738{
739 ASSERT(n>=0 && n<mNPar);
740
741 Param(n) = v;
742 if( ! fixParam[n] ) {
743 fixParam[n] = 1;
744 mNParFree--;
745 }
746 if(debugLevel>0) cout<<" SetFix "<<n
747 <<" v="<<v
748 <<" (Nfree="<<mNParFree
749 <<")"<<endl;
750}
751
752/*!
753 Pour fixer le parametre "n" a la valeur par defaut
754*/
755void GeneralFit::SetFix(int n)
756{
757 ASSERT(n>=0 && n<mNPar);
758 SetFix(n,Param(n));
759}
760
761/*!
762 Pour liberer le parametre "n"
763*/
764void GeneralFit::SetFree(int n)
765{
766 ASSERT(n>=0 && n<mNPar);
767
768 if( fixParam[n] ) {
769 fixParam[n] = 0;
770 mNParFree++;
771 if(debugLevel>0) cout<<" SetFree "<<n
772 <<" Step "<<stepParam(n)
773 <<" (Nfree="<<mNParFree<<")"<<endl;
774 if(stepParam(n)<=0.)
775 cout<<"ATTENTION SetFree["<<n<<"] avec step<=0 "
776 <<stepParam(n)<<endl;
777 }
778}
779
780/*!
781 Pour liberer tous les parametres
782*/
783void GeneralFit::SetFree()
784{
785 for(int i=0;i<mNPar;i++) SetFree(i);
786}
787
788//////////////////////////////////////////////////////////////////////
789/*!
790 Retourne la valeur du parametre "n"
791*/
792double GeneralFit::GetParm(int n)
793{
794 ASSERT(n>=0 && n<mNPar);
795 return Param(n);
796}
797
798/*!
799 Retourne les valeurs des parametres dans un vecteur.
800*/
801TVector<r_8> GeneralFit::GetParm()
802{
803return Param;
804}
805
806/*!
807 Retourne la valeur de l'erreur du parametre "n"
808*/
809double GeneralFit::GetParmErr(int n)
810{
811 ASSERT(n>=0 && n<mNPar);
812 return errParam(n);
813}
814
815/*!
816 Retourne la covariance pour les parametre `i' et `j'
817*/
818double GeneralFit::GetCoVar(int i,int j)
819{
820 ASSERT(i>=0 && i<mNPar && j>=0 && j<mNPar);
821 return ATGA(i,j);
822}
823
824//////////////////////////////////////////////////////////////////////
825/*!
826 Retourne la valeur du pas du parametre "n"
827*/
828double GeneralFit::GetStep(int n)
829{
830 ASSERT(n>=0 && n<mNPar);
831 return stepParam(n);
832}
833
834/*!
835 Retourne la valeur de la borne superieure du parametre "n"
836*/
837double GeneralFit::GetMax(int n)
838{
839 ASSERT(n>=0 && n<mNPar);
840 return maxParam(n);
841}
842
843/*!
844 Retourne la valeur de la borne inferieure du parametre "n"
845*/
846double GeneralFit::GetMin(int n)
847{
848 ASSERT(n>=0 && n<mNPar);
849 return minParam(n);
850}
851
852//////////////////////////////////////////////////////////////////////
853/*!
854 Impression du status du fit
855*/
856void GeneralFit::PrintStatus()
857{
858 cout<<"GeneralFit::PrintStatus"
859 <<" mData="<<mData
860 <<" mFunction="<<mFunction
861 <<" mFuncXi2="<<mFuncXi2
862 <<endl;
863 cout<<" mNVar="<<mNVar
864 <<" mNPar="<<mNPar
865 <<" mNParFree="<<mNParFree
866 <<" mNParBound="<<mNParBound
867 <<endl;
868 cout<<" Lambda_Fac="<<Lambda_Fac
869 <<" stopChi2="<<stopChi2
870 <<" maxStep="<<maxStep
871 <<" nStopMx="<<nStopMx<<" stopChi2SMx="<<stopChi2SMx
872 <<" nStopLent="<<nStopLent
873 <<" debugLevel="<<debugLevel
874 <<endl;
875 PrintParm();
876}
877
878/*!
879 Impression des resultats du fit
880*/
881void GeneralFit::PrintFit()
882{
883 cout<<"PrintFit: Chi2="<<Chi2
884 <<" Lambda="<<Lambda
885 <<" nStep="<<nStep
886 <<" nStop="<<nStop
887 <<" nStopL="<<nStopL
888 <<" nDDL="<<mNddl
889 <<endl;
890 PrintParm();
891}
892
893/*!
894 Impression des informations relatives au parametre "n"
895*/
896void GeneralFit::PrintParm(int n)
897{
898 ASSERT(n>=0 && n<mNPar);
899
900 cout<<"Par["<<n<<"] "<<nameParam[n]
901 <<" F"<<fixParam[n]
902 <<" B"<<boundParam[n]
903 <<" : "<<Param(n)
904 <<" +/- "<<errParam(n)
905 <<" : "<<stepParam(n)
906 <<" "<<minParam(n)
907 <<" "<<maxParam(n)
908 <<" : "<<Eps(n)
909 <<" "<<minStepDeriv(n)
910 <<endl;
911}
912
913/*!
914 Impression des informations relatives a tous les parametres
915*/
916void GeneralFit::PrintParm()
917{
918 cout<<"*** Parametres : fix bnd : par err : step min max : eps dmin\n";
919 for (int i=0; i<mNPar; i++) PrintParm(i);
920 cout<<endl;
921}
922
923//////////////////////////////////////////////////////////////////////
924/*!
925 Methode de fit.
926 \anchor GeneralFit_Fit
927 \verbatim
928 Fonction de fit de la fonction f(x,y,z,...:p1,p2,...,pn)
929 sur les donnees x[i],y[i],z[i],...,F[i],ErrF[i]
930 - Methode: fit des moindres carres dans le cas non lineaire
931 - Reference: Statistical and Computational Methods in Data Analysis
932 Siegmund Brandt, North-Holland 1970 p 204-206.
933 Introduction des limites pour la variation des parametres (cmv).
934 Increment des parametres selon la methode de Levenberg-Marquardt
935 (Numerical Recipes in C, chap 15 Modeling of Data, Nonlinear Models,
936 Levenberg-Marquardt Method p683)
937 - Gestion des parametres bornes:
938 si p est un parametre borne entre pmin et pmax, le parametre fitte est q
939 tel que q = tang((p-C)/D) .... p = C + D*atan(q)
940 ou C = (pmin+pmax)/2. et D = (pmax-pmin)/Pi
941 On a dq = (1+q**2)/D * dp .... dp = D/(1+q**2) * dq
942 et dF/dq = dF/dp * dp/dq = D/(1+q**2) * dF/dp
943 dF/dp = dF/dq * dq/dp = (1+q**2)/D * dF/dp
944 ^ q
945 | | *| "tang()"
946 | | *|
947 | | *|
948 | | * |
949 | | * |
950 | | * |
951 | | * |
952 Pmin| C| * |Pmax
953 --------------|---------------*---------------|--------------> p
954 -Pi/2| * |0 |Pi/2
955 | * | |
956 | * | |
957 | * | |
958 | * | |
959 |* | |
960 |* | |
961 |* | |
962 <------------------- D --------->
963
964 - Criteres de convergence, arrets standards:
965 - SOIT: le Chi2 est descendu de moins de stopChi2
966 entre l'iteration n et n+1
967 (stopChi2 est change par SetStopChi2)
968 - SOIT: 1. le chi2 est remonte de moins de stopChi2SMx et
969 2. les parametres libres ont varie de moins de Eps(i)
970 pendant les nStopmx dernieres iterations
971 Si nStopmx<=0, alors ce critere n'est pas applique (def=3).
972 (nStopmx,stopChi2SMx sont changes par SetStopMx, Eps par SetEps)
973
974 - Criteres de convergence, arrets par non-convergence:
975 - plus de "maxStep" iterations.
976
977 - Criteres de convergence, arrets speciaux:
978 - Si l'utilisateur a demande explicitement la methode d'arret
979 "SetStopLent()", arret si :
980 1. le Chi2 est descendu et
981 2. les parametres libres ont varies de moins de Eps
982 pendant les nStopLent dernieres iterations.
983 (nStopLent est change par SetStopLent, Eps par SetEps)
984
985 - Remarques diverses:
986 Les points avec erreurs <=0 ne sont pas utilises dans le fit.
987 Les bornes des parametres ne peuvent etre atteintes
988 - entrees:
989 la fonction est definie par une classe GeneralFunction
990 les donnees sont passees par une classe GeneralFitData
991 le nombre de parametres et le nombre de variables doivent etre
992 coherents entre GeneralFunction GeneralFitData GeneralFit
993 - Return:
994 la function elle meme retourne le nombre d'iterations du fit si succes
995 -1 : si le nombre de degre de liberte est <0
996 -10 : si l'inversion de la matrice des erreurs n'a pas ete possible
997 -11 : si un element diagonal de la matrice des covariances est <=0
998 -20 : si le fit n'a pas converge (nstep>nNstepMX)
999 -100-N : si le parametre "N" est initialise hors limites
1000 -200-N : si le parametre "N" atteint sa limite inferieure
1001 -300-N : si le parametre "N" atteint sa limite superieure
1002 \endverbatim
1003*/
1004int GeneralFit::Fit()
1005{
1006 volatile double oldChi2;
1007 TMatrix<r_8> COVAR(mNPar,mNPar);
1008 TVector<r_8> DA(mNPar);
1009 TVector<r_8> dparam(mNPar);
1010 TVector<r_8> paramTry(mNPar);
1011 TVector<r_8> param_tr(mNPar);
1012 TVector<r_8> paramTry_tr(mNPar);
1013 TVector<r_8> step_tr(mNPar);
1014 nStop = nStopL = nStep = 0;
1015 Chi2 = oldChi2 = 0.;
1016 Lambda = 0.001;
1017 mNddl = mData->NDataGood() - mNParFree;
1018 if(mNddl<0) return -1;
1019 mNtry++;
1020
1021 if(debugLevel>= 2)
1022 cout<<"\n********* DEBUT GENERALFIT.FIT() **************"<<endl;
1023
1024 // set matrices C,D dans le cas de parametres bornes
1025 if(mNParBound>0) Set_Bound_C_D();
1026
1027 if(debugLevel>= 2) PrintStatus();
1028
1029 // check de la coherence des operations et assignations
1030 CheckSanity();
1031
1032 // Pour les parametres bornes on verifie
1033 // qu'ils sont initialises dans leurs limites
1034 {for(int i=0;i<mNPar;i++) {
1035 if( !boundParam[i] || fixParam[i] ) continue;
1036 if( minParam(i)<Param(i) && Param(i)<maxParam(i) ) continue;
1037 /* if(debugLevel>= 1) */
1038 cout<<"Parametre "<<i<<" initialise hors limites "
1039 <<minParam(i)<<" < "<<Param(i)
1040 <<" < "<<maxParam(i)<<endl;
1041 return(-100-i);
1042 }}
1043
1044 // premier essai d'initialisation
1045 param_tr = p_vers_tr(Param);
1046 dparam = stepParam / 2.;
1047 put_in_limits_for_deriv(Param,dparam);
1048 if(mFunction!=NULL) mFunction->SetDeltaParm(dparam.Data());
1049 else if(mFuncXi2!=NULL) mFuncXi2->SetDeltaParm(dparam.Data());
1050 step_tr = dp_vers_dtr(stepParam,param_tr);
1051
1052 if(debugLevel>= 2) {
1053 cout<<"ESSAI numero 1: Param:"<<endl;
1054 cout<<Param;
1055 cout<<"param_tr:"<<endl;
1056 cout<<param_tr;
1057 cout<<"step_tr:"<<endl;
1058 cout<<step_tr;
1059 }
1060 if(mFunction!=NULL) TryFunc(Param,param_tr);
1061 else if(mFuncXi2!=NULL) TryXi2(Param,param_tr);
1062 ATGA = ATGA_Try;
1063 BETA = BETA_Try;
1064 oldChi2 = Chi2;
1065
1066 // Iterations
1067 while (1) {
1068 nStep++;
1069
1070 // un nouvel essai (si Lambda!=0)
1071 {for(int i=0; i<mNPar; i++)
1072 if(! fixParam[i] ) ATGA(i,i) *= 1 + Lambda;
1073 else ATGA(i,i) = 1.;}
1074
1075 // Calcul de la matrice des covariances
1076#ifdef __mac__
1077 COVAR = SimpleMatrixOperation<r_8>::Inverse(ATGA); /* $CHECK$ Reza 10/3/2000 */
1078#else
1079 TRY {
1080 COVAR = SimpleMatrixOperation<r_8>::Inverse(ATGA); /* $CHECK$ Reza 10/3/2000 */
1081 } CATCHALL {
1082 if(debugLevel>0) {
1083 cout<<"Pb inversion matrice ATGA:"<<endl;
1084 cout<<ATGA;
1085 }
1086 return(-10);
1087 } ENDTRY
1088#endif
1089
1090 if (debugLevel >= 3) {
1091 cout<<"Matrice (tA G A)^-1 = \n";
1092 cout<<COVAR;
1093 }
1094
1095 // calculs des deplacements a effectuer
1096 DA = COVAR * BETA;
1097 if (debugLevel >=2) {
1098 cout<<"Correction parametres DA : \n";
1099 cout<<DA;
1100 }
1101
1102
1103 //////////////////////////////////////////////////
1104 ////////////////// Arret du Fit //////////////////
1105 // si Lambda = 0, le fit a converge on s'arrete
1106 // ou bien on a trop d'iterations
1107 //////////////////////////////////////////////////
1108 if(Lambda == 0 || nStep > maxStep) {
1109 // trop d'iterations
1110 if(nStep>maxStep)
1111 cout<<"GeneralFit : pas de convergence"<<endl;
1112 // Probleme de matrice de covariance non-definie positive?
1113 bool bad_covar = false;
1114 {for(int i=0; i<mNPar; i++) {
1115 if( fixParam[i] ) errParam(i) = 0.;
1116 else {
1117 stepParam(i) = DA(i);
1118 if( COVAR(i,i)<=0. ) {
1119 if( debugLevel>0 )
1120 cout<<"Erreur: Par["<<i<<"]="<<param_tr(i)
1121 <<" ("<<Param(i)<<") COVAR()="<<COVAR(i,i)
1122 <<" step="<<DA(i)<<endl;
1123 errParam(i) = 0.;
1124 bad_covar = true;
1125 } else {
1126 errParam(i) = sqrt( COVAR(i,i) );
1127 }
1128 }
1129 }}
1130 // print de debug pour parametres bornes
1131 if(debugLevel>= 2) {
1132 cout<<"param_tr:"<<endl;
1133 cout<<param_tr;
1134 cout<<"stepParam_tr:"<<endl;
1135 cout<<stepParam;
1136 cout<<"errParam_tr:"<<endl;
1137 cout<<errParam;
1138 }
1139 // Calcul de la matrice des covariances
1140 {for(int i=0; i<mNPar; i++) {
1141 for(int j=0; j<mNPar; j++) {
1142 if( fixParam[i] || fixParam[j] ) {
1143 // Parametre fixe, on retourne l'identite
1144 if(i==j) ATGA(i,j) = 1.; else ATGA(i,j) = 0.;
1145 } else if( errParam(i)<=0. || errParam(j)<=0.) {
1146 // parametres avec mauvaise variance, on retourne 0
1147 ATGA(i,j) = 0;
1148 } else {
1149 // parametres OK
1150 ATGA(i,j) = COVAR(i,j)/(errParam(i)*errParam(j));
1151 }
1152 }
1153 }}
1154 if (debugLevel >= 1) {
1155 cout<<">>> Matrice des Covariances = \n";
1156 cout<<ATGA;
1157 }
1158 // Calcul du step et de l'erreur finale en tenant
1159 // compte des parametres bornes
1160 stepParam = dtr_vers_dp(stepParam,param_tr);
1161 errParam = dtr_vers_dp(errParam,param_tr);
1162 // Print si demande et code de retour.
1163 if (debugLevel>0 ) PrintFit();
1164 if(nStep>maxStep) return(-20);
1165 else if(bad_covar) return(-11);
1166 else return(nStep);
1167 }
1168 ////////////////////////////////////////////////////////
1169 ////////////////// Fin d'Arret du Fit //////////////////
1170 ////////////////////////////////////////////////////////
1171
1172 // Gestion des deplacements
1173 {for (int i=0; i<mNPar; i++) {
1174 if( fixParam[i] ) { DA(i) = 0; continue;}
1175 // le premier deplacement ne peut etre plus grand que stepParam
1176 if( nStep == 1 && fabs(DA(i)) > step_tr(i) ) {
1177 DA(i) = DA(i) < 0. ? -step_tr(i) : step_tr(i);
1178 if(debugLevel>1 ) cout<<"Excursion parametre "<<i
1179 <<" limitee a "<<DA(i)<<endl;
1180 }
1181 }}
1182 paramTry_tr = param_tr + DA;
1183 paramTry = tr_vers_p(paramTry_tr);
1184 dparam = dtr_vers_dp(DA,paramTry_tr);
1185 dparam /= 2.;
1186 put_in_limits_for_deriv(paramTry,dparam);
1187 {for(int i=0; i<mNPar; i++) {
1188 if( ! boundParam[i] ) continue;
1189 if(paramTry(i) <= minParam(i)) {
1190 if(debugLevel>0) cout<<"Parametre "<<i
1191 <<" limite au minimum"<<endl;
1192 Param(i) = minParam(i);
1193 return(-200-i);
1194 } else if (paramTry(i) >= maxParam(i)) {
1195 if(debugLevel>0) cout<<"Parametre "<<i
1196 <<" limite au maximum"<<endl;
1197 Param(i) = maxParam(i);
1198 return(-300-i);
1199 }
1200 }}
1201
1202 // Nouvel essai
1203 if(mFunction!=NULL) mFunction->SetDeltaParm(dparam.Data());
1204 else if(mFuncXi2!=NULL) mFuncXi2->SetDeltaParm(dparam.Data());
1205 if(debugLevel >= 2) {
1206 cout<<">>>>>>>>>>> ESSAI avec nouveaux parametres\n";
1207 cout<<"paramTry:\n";
1208 cout<<paramTry;
1209 cout<<"paramTry_tr:\n";
1210 cout<<paramTry_tr;
1211 cout<<"dparam:\n";
1212 cout<<dparam;
1213 }
1214 if(mFunction!=NULL) TryFunc(paramTry,paramTry_tr);
1215 else if(mFuncXi2!=NULL) TryXi2(paramTry,paramTry_tr);
1216
1217 if (debugLevel >= 2)
1218 cout<<"step "<<nStep<<" Chi2 : old="<<oldChi2
1219 <<" new="<<Chi2<<" d="<<Chi2-oldChi2<<endl;
1220 if(FileStep) write_in_step(Chi2,paramTry);
1221
1222 // *************************************************************
1223 // ****************** quelle strategie sur Lambda ???? *********
1224 // *************************************************************
1225 if (Chi2 < oldChi2) {
1226 // ****************** le Chi2 est descendu ******************
1227 nStop = 0;
1228 if(nStopLent>0) {
1229 // Arret special demande, comment se comporte les parametres?
1230 int k=0;
1231 for (int i=0; i<mNPar; i++) if( (!fixParam[i]) &&
1232 (fabs(param_tr(i)-paramTry_tr(i))<Eps(i))) k++;
1233 if (k==mNParFree) nStopL++; // Tous les parametres ont peu varies
1234 else nStopL=0;
1235 if (debugLevel>=2) cout<<k<<" parametres sur "<<mNParFree
1236 <<" ont peu varies, nStopL="<<nStopL<<endl;
1237 } else nStopL = 0;
1238 // Preparation des parametres pour iteration suivante
1239 ATGA = ATGA_Try;
1240 BETA = BETA_Try;
1241 param_tr = paramTry_tr;
1242 Param = paramTry;
1243 Lambda *= 1./Lambda_Fac;
1244 // Arret ?
1245 if (oldChi2-Chi2<stopChi2) {
1246 // arret normal, convergence
1247 Lambda = 0;
1248 if (debugLevel >= 2)
1249 cout<<"Arret>> demande car Chi2 decroit et oldChi2-Chi2= "
1250 <<oldChi2-Chi2<<"<"<<stopChi2<<endl;
1251 } else if (nStopLent>0 && nStopL >= nStopLent) {
1252 // arret demande par SetStopLent, variation lente des parametres
1253 Lambda = 0.;
1254 if (debugLevel >= 2)
1255 cout<<"Arret>> demande car Chi2 decroit et nStop(lent)= "
1256 <<nStopL<<">="<<nStopLent<<endl;
1257 }
1258 oldChi2 = Chi2;
1259 if (debugLevel >= 2) cout<<"Succes essai: Lambda divided by "
1260 <<Lambda_Fac<<" -> "<<Lambda<<endl;
1261 } else {
1262 // ****************** le Chi2 est remonte ******************
1263 nStopL = 0;
1264 if(nStopMx>0 && Chi2-oldChi2<stopChi2SMx) {
1265 // Il est remonte tres peu, comment se comporte les parametres?
1266 int k=0;
1267 for (int i=0; i<mNPar; i++) if( (!fixParam[i]) &&
1268 (fabs(param_tr(i)-paramTry_tr(i))<Eps(i))) k++;
1269 if (k==mNParFree) nStop++; // Tous les parametres ont peu varies
1270 else nStop=0;
1271 if (debugLevel>=2) cout<<k<<" parametres sur "<<mNParFree
1272 <<" ont peu varies, nStop="<<nStop<<endl;
1273 } else nStop = 0;
1274 // Preparation des parametres pour iteration suivante
1275 Lambda *= Lambda_Fac;
1276 // Arret ?
1277 if (nStopMx>0 && nStop>=nStopMx) {
1278 // arret normal, convergence car ci2 varie peu et parametres aussi
1279 Lambda = 0.;
1280 if (debugLevel >= 2)
1281 cout<<"Arret>> demande car Chi2 croit et nstop= "
1282 <<nStop<<">="<<nStopMx<<endl;
1283 }
1284 Chi2 = oldChi2;
1285 if (debugLevel >= 2)
1286 cout<<"Echec essai: Lambda multiplied by "<<Lambda_Fac
1287 <<" -> "<<Lambda<<" nStop="<<nStop<<endl;
1288 }
1289
1290 } // fin des iterations
1291}
1292
1293//////////////////////////////////////////////////////////////////////
1294/*!
1295 Recalcul du Chi2 a partir des parametres courants (`par==NULL')
1296 ou a partir du tableau de parametres `par'.
1297 Retourne le chi2 et le nombre de degres de liberte.
1298 Si nddl<0 probleme.
1299*/
1300double GeneralFit::ReCalChi2(int& nddl, double *par)
1301{
1302double c2 = -1.;
1303if(par==NULL) par = Param.Data();
1304if( mData->NData() <= 0 ) {nddl = -100; return 0.;}
1305
1306if( mFunction != NULL ) {
1307
1308 double e,result;
1309
1310 nddl = 0; c2 = 0.;
1311 for(int k=0; k<mData->NData(); k++) {
1312 if (! mData->mOK[k]) continue;
1313 e = mData->mErr[k];
1314 result = mFunction->Value(&mData->mXP[mNVar*k],par);
1315 c2 += (mData->mF[k]-result)*(mData->mF[k]-result)/(e*e);
1316 nddl++;
1317 }
1318 nddl -= mNParFree;
1319
1320 return c2;
1321
1322} else if( mFuncXi2 != NULL ) {
1323
1324 c2 = mFuncXi2->Value(*mData,par,nddl);
1325 nddl -= mNParFree;
1326 return c2;
1327
1328} else {
1329
1330 cout<<"GeneralFit::ReCalChi2_Erreur: mFunction && mFuncXi2 == NULL"<<endl;
1331 nddl = -1;
1332 return c2;
1333}
1334
1335}
1336
1337//////////////////////////////////////////////////////////////////////
1338/*!
1339 Retourne une structure ``GeneralFitData'' contenant
1340 les residus du fit (val-func) pour les points du fit.
1341 Si ``clean'' est ``true''
1342 seules les donnees valides de ``data'' sont copiees.
1343 Si ``clean'' est ``false'' (defaut) toutes les donnees
1344 sont copiees et la taille totale de ``data'' est allouee
1345 meme si elle est plus grande que la taille des donnees stoquees.
1346*/
1347GeneralFitData GeneralFit::DataResidus(bool clean)
1348{
1349if(!mData || !mFunction)
1350 throw(NullPtrError("GeneralFit::DataResidus: NULL pointer\n"));
1351GeneralFitData datres(*mData,clean);
1352for(int k=0; k<mData->NData(); k++)
1353 datres.mF[k] -= mFunction->Value(&datres.mXP[mNVar*k],Param.Data());
1354return datres;
1355}
1356
1357//////////////////////////////////////////////////////////////////////
1358/*!
1359 Retourne une structure ``GeneralFitData'' contenant
1360 les valeurs de la fonction fittee pour les points du fit.
1361 (voir commentaires pour ``clean'' dans ``DataResidus'')
1362*/
1363GeneralFitData GeneralFit::DataFunction(bool clean)
1364{
1365if(!mData || !mFunction)
1366 throw(NullPtrError("GeneralFit::DataFunction: NULL pointer\n"));
1367GeneralFitData datres(*mData,clean);
1368for(int k=0; k<mData->NData(); k++)
1369 datres.mF[k] = mFunction->Value(&datres.mXP[mNVar*k],Param.Data());
1370return datres;
1371}
1372
1373//////////////////////////////////////////////////////////////////////
1374/*!
1375 Imprime le commentaire lie a l'erreur rc retournee par Fit()
1376 (voir le commentaire de la methode `Fit()')
1377*/
1378void GeneralFit::PrintFitErr(int rc)
1379{
1380int n;
1381if(rc>0) return;
1382
1383if(rc==-1)
1384 cout<<"rc = "<<rc<<" : le nombre de degre de liberte est <0"<<endl;
1385
1386else if(rc==-10)
1387 cout<<"rc = "<<rc<<" : l'inversion de la matrice des erreurs n'a pas ete possible"<<endl;
1388
1389else if(rc==-11)
1390 cout<<"rc = "<<rc<<" : un element diagonal de la matrice des covariances est <=0"<<endl;
1391
1392else if(rc==-20)
1393 cout<<"rc = "<<rc<<" : le fit n'a pas converge (nstep>nNstepMX="<<maxStep<<")"<<endl;
1394
1395else if(rc>-200 && rc<=-100) {
1396 n = -100-rc;
1397 cout<<"rc = "<<rc<<" : le parametre "<<n<<" ("<<nameParam[n]
1398 <<") est initialise hors limites"<<endl;
1399}
1400
1401else if(rc>-300 && rc<=-200) {
1402 n = -200-rc;
1403 cout<<"rc = "<<rc<<" : le parametre "<<n<<" ("<<nameParam[n]
1404 <<") atteint sa limite inferieure"<<endl;
1405}
1406
1407else if(rc>-400 && rc<=-300) {
1408 n = -300-rc;
1409 cout<<"rc = "<<rc<<" : le parametre "<<n<<" ("<<nameParam[n]
1410 <<") atteint sa limite superieure"<<endl;
1411}
1412
1413else cout<<"rc = "<<rc<<" : type d'erreur inconnue"<<endl;
1414
1415}
1416
1417//////////////////////////////////////////////////////////////////////
1418// Fonctions privees
1419//////////////////////////////////////////////////////////////////////
1420
1421//////////////////////////////////////////////////////////////////////
1422void GeneralFit::write_in_step(double ci2,TVector<r_8>& par)
1423{
1424if(FileStep==NULL) return;
1425fprintf(FileStep,"%d %d %f",mNtry,nStep,ci2);
1426for(int i=0; i<mNPar; i++) fprintf(FileStep," %f",par(i));
1427fprintf(FileStep,"\n");
1428}
1429
1430//////////////////////////////////////////////////////////////////////
1431void GeneralFit::TryFunc(TVector<r_8>& par,TVector<r_8>& par_tr)
1432{
1433 BETA_Try = 0;
1434 ATGA_Try = 0;
1435 Chi2 = 0;
1436 TVector<r_8> deriv(mNPar);
1437 TVector<r_8> derivtr(mNPar);
1438 double result;
1439
1440 for(int k=0; k<mData->NData(); k++) {
1441 if (! mData->mOK[k]) continue;
1442 double e = mData->mErr[k];
1443 if(mNParBound==0)
1444 result = mFunction->Val_Der(&mData->mXP[mNVar*k]
1445 ,par.Data(),derivtr.Data());
1446 else {
1447 result = mFunction->Val_Der(&mData->mXP[mNVar*k]
1448 ,par.Data(),deriv.Data());
1449 dtr_vers_dp(deriv,par_tr,derivtr);
1450 }
1451 double Gkk = 1/(e*e);
1452 double Ck = mData->mF[k] - result;
1453 Chi2 += Ck*Ck*Gkk;
1454 for(int j=0; j<mNPar; j++) {
1455 if( fixParam[j] ) continue;
1456 for(int i=0; i<mNPar; i++)
1457 if(!fixParam[i]) ATGA_Try(i,j) += derivtr(i)*Gkk*derivtr(j);
1458 BETA_Try(j) += derivtr(j) * Gkk * Ck;
1459 }
1460 }
1461
1462 if (debugLevel >= 3) {
1463 cout<<"Try: matrice ( At * G * A )_Try\n";
1464 cout<<ATGA_Try;
1465 cout<<"Try: beta_Try:\n";
1466 cout<<BETA_Try;
1467 }
1468}
1469
1470//////////////////////////////////////////////////////////////////////
1471void GeneralFit::TryXi2(TVector<r_8>& par,TVector<r_8>& par_tr)
1472{
1473 double c, *parloc;
1474 BETA_Try = 0;
1475 ATGA_Try = 0;
1476 Chi2 = 0;
1477
1478 parloc = par.Data(); // He oui, encore ces ... de const*
1479 Chi2 = mFuncXi2->Value(*mData,parloc,mNddl);
1480 mNddl -= mNParFree;
1481
1482 // Calcul des derivees du Xi2 (vecteur du gradient)
1483 {for(int i=0;i<mNPar; i++) {
1484 if( fixParam[i] ) continue;
1485 c = c_dtr_vers_dp(i,par_tr(i));
1486 BETA_Try(i) = -0.5 * mFuncXi2->Derivee(*mData,i,parloc) * c;
1487 }}
1488
1489 // Calcul des derivees 2sd du Xi2 (matrice de courbure ou 0.5*Hessien)
1490 double c1,c2;
1491 {for(int i=0;i<mNPar; i++) {
1492 if( fixParam[i] ) continue;
1493 c1 = c_dtr_vers_dp(i,par_tr(i));
1494 for(int j=0;j<mNPar; j++) {
1495 if( fixParam[j] ) continue;
1496 c2 = c_dtr_vers_dp(j,par_tr(j));
1497 ATGA_Try(i,j) = 0.5 * mFuncXi2->Derivee2(*mData,i,j,parloc) *c1*c2;
1498 }
1499 }}
1500 // et on symetrise car d/di(dC2/dj) = d/dj(dC2/di) mathematiquement
1501 // mais malheureusement pas numeriquement.
1502 if( mNPar>1) {
1503 for(int i=0;i<mNPar-1; i++) {
1504 if( fixParam[i] ) continue;
1505 for(int j=i+1;j<mNPar; j++) {
1506 if( fixParam[j] ) continue;
1507 c1 = 0.5*(ATGA_Try(i,j) + ATGA_Try(j,i));
1508 ATGA_Try(i,j) = c1;
1509 ATGA_Try(j,i) = c1;
1510 }
1511 }
1512 }
1513
1514 if (debugLevel >= 3) {
1515 cout<<"Try: matrice ( At * G * A )_Try\n";
1516 cout<<ATGA_Try;
1517 cout<<"Try: beta_Try:\n";
1518 cout<<BETA_Try;
1519 }
1520}
1521
1522//////////////////////////////////////////////////////////////////////
1523void GeneralFit::CheckSanity()
1524{
1525 ASSERT( mData != NULL );
1526 ASSERT( mFunction != NULL || mFuncXi2 != NULL );
1527 if( mFunction != NULL ) {
1528 ASSERT( mFunction->NVar() == mNVar );
1529 ASSERT( mData->NVar() == mNVar );
1530 }
1531 ASSERT( mNParFree > 0 && mNParFree <= mNPar );
1532 ASSERT( mNParBound >= 0 && mNParBound <= mNPar );
1533 ASSERT( mNParFree <= mData->NDataGood() );
1534}
1535
1536//////////////////////////////////////////////////////////////////////
1537/*!
1538 \verbatim
1539 C = (min+max)/2
1540 D = (max-min)/Pi
1541 \endverbatim
1542*/
1543void GeneralFit::Set_Bound_C_D(int i)
1544{
1545 // ASSERT(i>=0 && i<mNPar);
1546 C(i) = D(i) = 0.;
1547 if( !boundParam[i] || fixParam[i] ) return;
1548 C(i) = (maxParam(i)+minParam(i))/2.;
1549 D(i) = (maxParam(i)-minParam(i))/M_PI;
1550}
1551
1552//////////////////////////////////////////////////////////////////////
1553void GeneralFit::Set_Bound_C_D()
1554{
1555 for(int i=0;i<mNPar;i++) Set_Bound_C_D(i);
1556 if(debugLevel>= 2) {
1557 cout<<"Set_Bound_C_D: C=\n";
1558 cout<<C;
1559 cout<<"Set_Bound_C_D: D=\n";
1560 cout<<D;
1561 }
1562}
1563
1564//////////////////////////////////////////////////////////////////////
1565/*!
1566 \verbatim
1567 tr = tan( (p-C)/D )
1568 \endverbatim
1569*/
1570double GeneralFit::p_vers_tr(int i,double p)
1571{
1572 // ASSERT(i>=0 && i<mNPar);
1573 double tr = p;
1574 if(boundParam[i]) tr = tan((p-C(i))/D(i));
1575 return(tr);
1576}
1577
1578//////////////////////////////////////////////////////////////////////
1579TVector<r_8> GeneralFit::p_vers_tr(TVector<r_8> const& p)
1580{
1581 TVector<r_8> tr(p,false);
1582 for(int i=0;i<mNPar;i++) {
1583 if( fixParam[i] || ! boundParam[i] ) continue;
1584 tr(i) = p_vers_tr(i,p(i));
1585 }
1586 return(tr);
1587}
1588
1589//////////////////////////////////////////////////////////////////////
1590void GeneralFit::p_vers_tr(TVector<r_8> const& p,TVector<r_8>& tr)
1591{
1592 for(int i=0;i<mNPar;i++) {
1593 if( fixParam[i] ) continue;
1594 if( ! boundParam[i] ) tr(i) = p(i);
1595 else tr(i) = tan((p(i)-C(i))/D(i));
1596 }
1597}
1598
1599//////////////////////////////////////////////////////////////////////
1600/*!
1601 \verbatim
1602 p = C+D*atan(tr)
1603 \endverbatim
1604*/
1605double GeneralFit::tr_vers_p(int i,double tr)
1606{
1607 // ASSERT(i>=0 && i<mNPar);
1608 double p = tr;
1609 if(boundParam[i]) p = C(i)+D(i)*atan(tr);
1610 return(p);
1611}
1612
1613//////////////////////////////////////////////////////////////////////
1614TVector<r_8> GeneralFit::tr_vers_p(TVector<r_8> const& tr)
1615{
1616 TVector<r_8> p(tr,false);
1617 for(int i=0;i<mNPar;i++) {
1618 if( fixParam[i] || ! boundParam[i] ) continue;
1619 p(i) = tr_vers_p(i,tr(i));
1620 }
1621 return(p);
1622}
1623
1624//////////////////////////////////////////////////////////////////////
1625void GeneralFit::tr_vers_p(TVector<r_8> const& tr,TVector<r_8>& p)
1626{
1627 for(int i=0;i<mNPar;i++) {
1628 if( fixParam[i] ) continue;
1629 if( ! boundParam[i] ) p(i) = tr(i);
1630 else p(i) = C(i)+D(i)*atan(tr(i));
1631 }
1632}
1633
1634//////////////////////////////////////////////////////////////////////
1635/*!
1636 \verbatim
1637 dtr = (1+tr**2)/D * dp = (1+tan( (p-C)/D )**2)/D * dp = coeff * dp
1638 attention: df/dp = (1+tr**2)/D * dF/dtr = coeff * dF/dtr
1639 \endverbatim
1640*/
1641double GeneralFit::c_dp_vers_dtr(int i,double tr)
1642{
1643 // ASSERT(i>=0 && i<mNPar);
1644 double coeff = 1.;
1645 if(boundParam[i]) coeff = (1.+tr*tr)/D(i);
1646 return(coeff);
1647}
1648
1649//////////////////////////////////////////////////////////////////////
1650TVector<r_8> GeneralFit::dp_vers_dtr(TVector<r_8> const& dp,TVector<r_8> const& tr)
1651{
1652 TVector<r_8> dtr(dp,false);
1653 for(int i=0;i<mNPar;i++) {
1654 if( fixParam[i] || ! boundParam[i] ) continue;
1655 dtr(i) *= c_dp_vers_dtr(i,tr(i));
1656 }
1657 return(dtr);
1658}
1659
1660//////////////////////////////////////////////////////////////////////
1661void GeneralFit::dp_vers_dtr(TVector<r_8> const& dp,TVector<r_8> const& tr,TVector<r_8>& dtr)
1662{
1663 for(int i=0;i<mNPar;i++) {
1664 if( fixParam[i] ) continue;
1665 if( ! boundParam[i] ) dtr(i) = dp(i);
1666 else dtr(i) = (1.+tr(i)*tr(i))/D(i) * dp(i);
1667 }
1668}
1669
1670//////////////////////////////////////////////////////////////////////
1671/*!
1672 \verbatim
1673 dp = D/(1+tr**2) * dtr = coeff * dtr
1674 attention: df/dtr = D/(1+tr**2) * dF/dp = coeff * dF/dp
1675 \endverbatim
1676*/
1677double GeneralFit::c_dtr_vers_dp(int i,double tr)
1678{
1679 // ASSERT(i>=0 && i<mNPar);
1680 double coeff = 1.;
1681 if(boundParam[i]) coeff = D(i)/(1.+tr*tr);
1682 return(coeff);
1683}
1684
1685//////////////////////////////////////////////////////////////////////
1686TVector<r_8> GeneralFit::dtr_vers_dp(TVector<r_8> const& dtr,TVector<r_8> const& tr)
1687{
1688 TVector<r_8> dp(dtr,false);
1689 for(int i=0;i<mNPar;i++) {
1690 if( fixParam[i] || ! boundParam[i] ) continue;
1691 dp(i) *= c_dtr_vers_dp(i,tr(i));
1692 }
1693 return(dp);
1694}
1695
1696//////////////////////////////////////////////////////////////////////
1697// inline fonction pour aller + vite dans le try()
1698//void GeneralFit::dtr_vers_dp(TVector<r_8> const& dtr,TVector<r_8> const& tr,TVector<r_8>& dp)
1699
1700//////////////////////////////////////////////////////////////////////
1701/*!
1702 \verbatim
1703 1-/ Redefinit dp pour qu'il soit superieur a minStepDeriv
1704 2-/ Redefinit dp pour que p+/-dp reste dans les limites (parametre borne)
1705 Si hors limites alors:
1706 p-dp <= min_p : dp = (p-min_p)*dist
1707 p+dp >= max_p : dp = (max_p-p)*dist
1708 \endverbatim
1709*/
1710int GeneralFit::put_in_limits_for_deriv(TVector<r_8> const& p,TVector<r_8>& dp,double dist)
1711{
1712 int nchanged = 0;
1713 bool changed;
1714 double dp_old;
1715
1716 for(int i=0;i<mNPar;i++) {
1717 if( fixParam[i] ) {dp(i)=0.; continue;} // Pas calcul derivee pour param fixe
1718
1719 if( fabs(dp(i))<minStepDeriv(i) ) {
1720 // On ne redefinit dp que si minStepDeriv>0.
1721 dp_old = dp(i);
1722 if(dp(i)>=0.) dp(i) = minStepDeriv(i); else dp(i) = -minStepDeriv(i);
1723 if(debugLevel>=2)
1724 cout<<"put_in_limits_for_deriv(range) dp["<<i<<"]=abs("<<dp_old
1725 <<") <"<<minStepDeriv(i)<<" changed to "<<dp(i)<<endl;
1726 }
1727
1728 if( !boundParam[i] ) continue;
1729
1730 changed = false;
1731 if( p(i)-dp(i)<=minParam(i) ) {
1732 dp_old = dp(i);
1733 dp(i) = dist*(p(i)-minParam(i));
1734 changed = true;
1735 if(debugLevel>=2)
1736 cout<<"put_in_limits_for_deriv(min) p["<<i<<"]="<<p(i)<<" >="
1737 <<minParam(i)<<" .. dp="<<dp_old<<" -> dp="<<dp(i)<<endl;
1738 }
1739
1740 if( p(i)+dp(i)>=maxParam(i) ) {
1741 dp_old = dp(i);
1742 dp(i) = dist*(maxParam(i)-p(i));
1743 changed = true;
1744 if(debugLevel>=2)
1745 cout<<"put_in_limits_for_deriv(max) p["<<i<<"]="<<p(i)<<" <="
1746 <<maxParam(i)<<" .. dp="<<dp_old<<" -> dp="<<dp(i)<<endl;
1747 }
1748
1749 if(changed) nchanged++;
1750 }
1751
1752 return nchanged;
1753}
1754
Note: See TracBrowser for help on using the repository browser.