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

Last change on this file since 2650 was 2615, checked in by cmv, 21 years ago

using namespace sophya enleve de machdefs.h, nouveau sopnamsp.h cmv 10/09/2004

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