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

Last change on this file since 774 was 774, checked in by ansari, 26 years ago

Adaptation aux modifs de TMatrixRC<T> - Reza 10/3/2000

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