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

Last change on this file since 2506 was 2506, checked in by ansari, 22 years ago

Remplacement THROW par throw - Reza 15/03/2004

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