#include #include #include #include #include #include "piafitting.h" #include "strutil.h" #include "generalfit.h" #include "fct1dfit.h" #include "fct2dfit.h" #include "matrix.h" #include "cvector.h" #include "ntuple.h" #include "cimage.h" #include "histos.h" #include "histos2.h" #include "ntuple.h" #include "hisprof.h" #include "nobjmgr.h" #include "pistdimgapp.h" //// ---------- Classe de fenetre de fit interactive ------------ class PIAFitterWind : public PIWindow { public : PIAFitterWind(PIStdImgApp* par, PIAFitter* fiter); virtual ~PIAFitterWind(); virtual void Show(); virtual void Process(PIMessage msg, PIMsgHandler* sender, void* data=NULL); inline void SetObjName(string& nom) { oname = nom; } protected : PIStdImgApp* dap; PIAFitter* fitter; PIOptMenu* pom[2]; PILabel* lab[2]; // Maximum 20 parametres PIText* txt[2]; // " " " PIButton* but[2]; PICheckBox* ckb[2]; string oname; }; ///////////////////// Fit 1D et 2D ////////////////////////// PIAFitterWind* fwind = NULL; /* --Methode-- */ PIAFitter::PIAFitter(PIACmd *piac, PIStdImgApp* app) { string kw, usage; kw = "fit"; usage = "Fitting function to DataObjects (Histo, Histo2D, Vector, ...)"; usage += "\n Usage: fit nomobj func [Options]"; usage += "\n [p:p1,...,pn s:s1,...,sn m:m1,...,mn M:M1,...,Mn o:... o:...]"; piac->RegisterCommand(kw, usage, this, "Fitting"); kw = "fitw"; usage = "Interactive Window Fit"; usage += "\n Usage: fit nomobj "; piac->RegisterCommand(kw, usage, this, "Fitting"); // Je cree une seule copie de PIAFitterWind // Attention, ca ne marchera pas si on detruit this if (fwind == NULL) fwind = new PIAFitterWind(app, this); } /* --Methode-- */ PIAFitter::~PIAFitter() { } int PIAFitter::Execute(string& kw, vector& tokens) { // Fit 1D sur objets 1D. Egalement Fit 2D sur objets 2D. if (kw == "fit") { if (tokens.size() < 2) { cout <<"Usage:fit nomobj func \n" <<" [p:p1,...,pn s:s1,...,sn m:m1,...,mn M:M1,...,Mn o:... o:...]\n"; return(0); } string p=""; string s=""; string m=""; string M=""; string O=""; if (tokens.size()>2) for(int ip=2;ipShow(); } return(0); } /* --Methode-- cmv 13/10/98 */ void PIAFitter::Fit12D(string& nom, string& func, string par,string step,string min,string max, string opt) //| --------------- Fit d'objets a 1 et 2 dimensions --------------- //| nom : nom de l'objet qui peut etre: //| fit-1D: Vector,Histo1D,HProf ou GeneraFitData(1D) //| fit-2D: Matrix,Histo2D,Image ou GeneraFitData(2D) //| func : pnn : fit polynome degre nn avec classe Poly (lineaire) 1D ou 2D //| : Pnn : fit polynome degre nn avec GeneralFit (non-lineaire) 1D ou 2D //| : gnn : fit gaussienne (hauteur) + polynome de degre nn 1D //| : g : fit gaussienne (hauteur) 1D //| : enn : fit exponentielle + polynome de degre nn 1D //| : e : fit exponentielle 1D //| : Gnn : fit gaussienne (volume) + polynome de degre nn 1D //| : G : fit gaussienne (volume) 1D //| : : fit gaussienne+fond (volume) 2D //| : Gi : fit gaussienne+fond integree (volume) 2D //| : d : fit DL de gaussienne+fond (volume) 2D //| : di : fit DL de gaussienne+fond integree (volume) 2D //| : D : fit DL de gaussienne+fond avec coeff variable p6 (volume) 2D //| : Di : fit DL de gaussienne+fond integree avec coeff variable p6 (volume) 2D //| : M : fit Moffat+fond (expos=p6) (volume) 2D //| : Mi : fit Moffat+fond integree (expos=p6) (volume) 2D //| par : p1,...,pn : valeur d'initialisation des parametres (def=0) //| step : s1,...,sn : valeur des steps de depart (def=1) //| min : m1,...,mn : valeur des minima (def=1) //| max : M1,...,Mn : valeur des maxima (def=-1) (max<=min : pas de limite) //| opt : options "Eaa.b,eaa.b,f,r,caa.b,Xaa.b" //| f : generation d'un Objet identique contenant la fonction fittee //| r : generation d'un Objet identique contenant les residus //| Xaa.b : aa.b valeur du DXi2 d'arret (def=1.e-3) //| Naa : aa nombre maximum d'iterations (def=100) //| la.b : niveau "a.b" de print: a=niveau de print Fit1/2D //| b=niveau de debug GeneralFit //| Ii1/i2 numeros des bins X de l'histos utilises pour le fit [i1,i2] //|2D Jj1/j2 numeros des bins Y de l'histos utilises pour le fit [j1,j2] //| - L'erreur est celle associee a l'objet (si elle existe), //| elle est mise a 1 sinon, sauf si E... ou e... est precise: //| Eaa.b : si |val|>=1 erreur = aa.b*sqrt(|val|) //| si |val|<1 erreur = aa.b //| si aa.b <=0 alors aa.b=1.0 //| E seul est equivalent a E1.0 //| eaa.b : erreur = aa.b //| si aa.b <=0 alors aa.b=1.0 //| e seul est equivalent a e1.0 //| xaa.b : demande de centrage: on fit x-aa.b au lieu de x) //| x : demande de centrage: on fit x-xc au lieu de x //| avec xc=abscisse du milieu de l'histogramme //| Actif pour exp+poly 1D, poly 1D //| pour gauss+poly 1D, xc est le centre de la gaussienne. //|2D yaa.b et y : idem "xaa.b et x" mais pour y { NamedObjMgr omg; AnyDataObj* obj = omg.GetObj(nom); if (obj == NULL) { cout<<"PIAFitter::Fit12D() Error , Pas d'objet de nom "<NElts(); nbiny = 1; } else if ( (typeid(*obj) == typeid(HProf)) || (typeid(*obj) == typeid(Histo)) ) { ndim = 1; h = (Histo*) obj; nbinx = h->NBins(); nbiny = 1; } else if (typeid(*obj) == typeid(Matrix)) { ndim = 2; m = (Matrix*) obj; nbinx = m->NCol(); nbiny = m->NRows(); } else if (typeid(*obj) == typeid(Histo2D)) { ndim = 2; h2 = (Histo2D*) obj; nbinx = h2->NBinX(); nbiny = h2->NBinY(); } else if (typeid(*obj) == typeid(GeneralFitData)) { g = (GeneralFitData*) obj; nbinx = g->NData(); nbiny = 1; if( g->NVar()==1) ndim = 1; else if(g->NVar()==2) ndim = 2; else { cout<<"GeneralFitData ne peut avoir que 1 ou 2 variables d'abscisse: " <<((GeneralFitData*) obj)->NVar()<(obj)) { ndim = 2; im = (RzImage*) obj; nbinx = im->XSize(); nbiny = im->YSize(); } else { cout<<"PIAFitter::Fit12D() Error , Objet n'est pas un " <<"Histo1D/HProf/Vector/Histo2D/Image/Matrix/GeneralFitData "<=nbinx)? 0: O.i1; O.i2 = (O.i2<0||O.i2>=nbinx||O.i2=2) { O.j1 = (O.j1<0||O.j1>=nbiny)? 0: O.j1; O.j2 = (O.j2<0||O.j2>=nbiny||O.j2XMin()+h->XMax())/2.; else if(h2) O.xc = (h2->XMin()+h2->XMax())/2.; else if(g) {double mini,maxi; g->GetMinMax(2,mini,maxi); O.xc=(mini+maxi)/2.;} else if(im) {O.xc = im->XOrg() * im->XPxSize()*(O.i2-O.i1+1)/2.;} } if(O.polcy==2 && ndim>=2) { if(m) O.yc = (O.j2-O.j1+1)/2.; if(h2) O.yc = (h2->YMin()+h2->YMax())/2.; if(g) {double mini,maxi; g->GetMinMax(12,mini,maxi); O.yc=(mini+maxi)/2.;} if(im) {O.yc = im->YOrg() * im->YPxSize()*(O.j2-O.j1+1)/2.;} } if(O.lp>0) cout<<"Fit["<BinCenter(i); f=(*h)(i); e=(h->HasErrors())?h->Error(i):1.;} else if(m) {x=(double) i; y=(double) j; f=(*m)(j,i); e=1.;} else if(h2) {float xf,yf; h2->BinCenter(i,j,xf,yf); x=(double)xf; y=(double)yf; f=(*h2)(i,j); e=(h2->HasErrors())?h2->Error(i,j):1.;} else if(im) {x=im->XOrg()+(i+0.5)*im->XPxSize(); y=im->YOrg()+(j+0.5)*im->YPxSize(); f=im->DValue(i,j); e=1.;} else if(g&&ndim==1) {x= g->X(i); f=g->Val(i); e=g->EVal(i);} else if(g&&ndim==2) {x= g->X(i); y= g->Y(i); f=g->Val(i); e=g->EVal(i);} else x=y=f=e=0.; // Gestion des erreurs a utiliser if(O.err_e>0.) e=O.err_e; else if(O.err_E>0.) {e=(f<-1.||f>1.)?O.err_E*sqrt(fabs(f)):O.err_E;} // Remplissage de generalfit if(func[0]=='p') {x -= O.xc; if(ndim>=2) y -= O.yc;} if(ndim==1) mydata.AddData1(x,f,e); else if(ndim==2) mydata.AddData2(x,y,f,e); }} if(mydata.NData()<=0) {cout<<"Pas de donnees dans GeneralFitData: "<1) { mydata.PrintStatus(); mydata.PrintData(0); mydata.PrintData(mydata.NData()-1); } //////////////////////////////////////////// // Identification de la fonction a fitter // //////////////////////////////////////////// GeneralFunction* myfunc = NULL; if(func[0]=='p' && ndim==1) { // Fit de polynome sans passer par les GeneralFit int degre = 0; if(func.length()>1) sscanf(func.c_str()+1,"%d",°re); cout<<"Fit (lineaire) 1D polynome de degre "<1) sscanf(func.c_str()+1,"%d",°re); cout<<"Fit d'exponentielle+polynome 1D de degre "<=0) myf = new Exp1DPol((unsigned int)degre,O.xc); else myf = new Exp1DPol(O.xc); myfunc = myf; } else if(func[0]=='g' && ndim==1) { // Fit de gaussienne en hauteur int degre =-1; if(func.length()>1) sscanf(func.c_str()+1,"%d",°re); cout<<"Fit de Gaussienne_en_hauteur+polynome 1D de degre "<=0) myf = new Gauss1DPol((unsigned int)degre,((O.polcx)?true:false)); else { bool bfg = (O.polcx)?true:false; myf = new Gauss1DPol(bfg); } myfunc = myf; } else if(func[0]=='G' && ndim==1) { // Fit de gaussienne en volume int degre =-1; if(func.length()>1) sscanf(func.c_str()+1,"%d",°re); cout<<"Fit de Gaussienne_en_volume+polynome 1D de degre "<=0) myf = new GaussN1DPol((unsigned int)degre,((O.polcx)?true:false)); else { bool bfg = (O.polcx)?true:false; myf = new GaussN1DPol(bfg); } myfunc = myf; } else if(func[0]=='p' && ndim==2) { // Fit de polynome 2D sans passer par les GeneralFit int degre = 0; if(func.length()>1) sscanf(func.c_str()+1,"%d",°re); cout<<"Fit (lineaire) polynome 2D de degre "<1) if(func[1]=='i') integ=1; cout<<"Fit de Gaussienne+Fond 2D integ="<1) if(func[1]=='i') integ=1; cout<<"Fit de DL de Gaussienne+Fond 2D integ="<1) if(func[1]=='i') integ=1; cout<<"Fit de DL de Gaussienne+Fond avec coeff variable (p6) 2D integ="<1) if(func[1]=='i') integ=1; cout<<"Fit de Moffat+Fond (expos=p6) 2D integ="<NPar()>Par.NElts()) {cout<<"Trop de parametres: "<NPar()<<">"<NPar();i++) { char str[10]; sprintf(str,"P%d",i); myfit.SetParam(i,str,Par(i),Step(i),Min(i),Max(i)); }} if(O.lp>1) myfit.PrintFit(); double c2r = -1.; int rcfit = (double) myfit.Fit(); if(O.lp>0) myfit.PrintFit(); if(rcfit>0) { c2r = myfit.GetChi2Red(); cout<<"C2r_Reduit = "<FitResidus(myfit); if(ob) omg.AddObj(ob,nomres);} if(O.okfun) {Vector* ob = v->FitFunction(myfit); if(ob) omg.AddObj(ob,nomfun);} } else if(h) { if(O.okres) {Histo* ob = h->FitResidus(myfit); if(ob) omg.AddObj(ob,nomres);} if(O.okfun) {Histo* ob = h->FitFunction(myfit); if(ob) omg.AddObj(ob,nomfun);} } else if(m) { if(O.okres) {Matrix* ob = m->FitResidus(myfit); if(ob) omg.AddObj(ob,nomres);} if(O.okfun) {Matrix* ob = m->FitFunction(myfit); if(ob) omg.AddObj(ob,nomfun);} } else if(h2) { if(O.okres) {Histo2D* ob = h2->FitResidus(myfit); if(ob) omg.AddObj(ob,nomres);} if(O.okfun) {Histo2D* ob = h2->FitFunction(myfit); if(ob) omg.AddObj(ob,nomfun);} } else if(im) { if(O.okres) {RzImage* ob = im->FitResidus(myfit); if(ob) omg.AddObj(ob,nomres);} if(O.okfun) {RzImage* ob = im->FitFunction(myfit); if(ob) omg.AddObj(ob,nomfun);} } else if(g) { if(O.okres) {GeneralFitData* ob = g->FitResidus(myfit); if(ob) omg.AddObj(ob,nomres);} if(O.okfun) {GeneralFitData* ob = g->FitFunction(myfit); if(ob) omg.AddObj(ob,nomfun);} } } // Nettoyage if(myfunc) delete myfunc; return; } /* --Function static propre aux routines de fit 1D et 2D-- cmv 13/10/98 */ void PIAFitter::DecodeFitsOptions(string par,string step,string min,string max,string opt ,Vector& Par,Vector& Step,Vector& Min,Vector& Max,DFOPTIONS& O) //| Pour decoder les "string" et remplir les vecteurs du fit (cf commentaires dans Fit1D) { // set des vecteurs et decodage des string correspondantes int NParMax = 100; Par.Realloc(NParMax); Step.Realloc(NParMax); Min.Realloc(NParMax); Max.Realloc(NParMax); { Vector* v=NULL; string* s=NULL; {for(int i=0;ilength()>0) *s += ","; for(int i=0;ilength()<=0) break; sscanf(s->c_str(),"%lf",&(*v)(i)); size_t p = s->find_first_of(',') + 1; if(p>=s->length()) *s = ""; else *s = s->substr(p); } } } // Decodage de options de opt O.okres = O.okfun = 0; O.polcx = O.polcy = 0; O.xc = O.yc = 0.; O.stc2 = 1.e-3; O.nstep = 100; O.err_e = O.err_E = -1.; O.lp = 1; O.lpg = 0; O.i1 = O.j1 = O.i2 = O.j2 = -1; if(opt.length()<=0) return; opt = "," + opt + ","; if(strstr(opt.c_str(),",r,")) O.okres = 1; // residus if(strstr(opt.c_str(),",f,")) O.okfun = 1; // fonction fittee if(strstr(opt.c_str(),",x")) { // Demande de centrage (fit X=x-xc) O.polcx = 2; // Le centrage est calcule automatiquement size_t p = opt.find(",x"); size_t q = opt.find_first_of(',',p+1); string dum = opt.substr(p,q-p); if(dum.length()>2) { sscanf(dum.c_str(),",x%lf",&O.xc); O.polcx = 1; // Le centrage est fixe par la valeur lue } } if(strstr(opt.c_str(),",y")) { // Demande de centrage (fit Y=y-yc) O.polcy = 2; // Le centrage est calcule automatiquement size_t p = opt.find(",y"); size_t q = opt.find_first_of(',',p+1); string dum = opt.substr(p,q-p); if(dum.length()>2) { sscanf(dum.c_str(),",y%lf",&O.yc); O.polcy = 1; // Le centrage est fixe par la valeur lue } } if(strstr(opt.c_str(),",E")) { // Erreurs imposees a "sqrt(val)" ou "aa.b*sqrt(val)" size_t p = opt.find(",E"); size_t q = opt.find_first_of(',',p+1); string dum = opt.substr(p,q-p); if(dum.length()>2) sscanf(dum.c_str(),",E%lf",&O.err_E); if(O.err_E<=0.) O.err_E = 1.; O.err_e=-1.; } if(strstr(opt.c_str(),",e")) { // Erreurs imposees a "1" ou "aa.b" size_t p = opt.find(",e"); size_t q = opt.find_first_of(',',p+1); string dum = opt.substr(p,q-p); if(dum.length()>2) sscanf(dum.c_str(),",e%lf",&O.err_e); if(O.err_e<=0.) O.err_e = 1.; O.err_E=-1.; } if(strstr(opt.c_str(),",X")) { // Valeur du StopChi2 size_t p = opt.find(",X"); size_t q = opt.find_first_of(',',p+1); string dum = opt.substr(p,q-p); if(dum.length()>2) sscanf(dum.c_str(),",X%lf",&O.stc2); if(O.stc2<=0.) O.stc2 = 1.e-3; } if(strstr(opt.c_str(),",N")) { // Nombre maximum d'iterations size_t p = opt.find(",N"); size_t q = opt.find_first_of(',',p+1); string dum = opt.substr(p,q-p); if(dum.length()>2) sscanf(dum.c_str(),",N%d",&O.nstep); if(O.nstep<2) O.nstep = 100; } if(strstr(opt.c_str(),",l")) { // niveau de print size_t p = opt.find(",l"); size_t q = opt.find_first_of(',',p+1); string dum = opt.substr(p,q-p); float ab; if(dum.length()>2) sscanf(dum.c_str(),",l%f",&ab); if(ab<0) ab = 0.; O.lp = (int) ab; O.lpg = int(10.*(ab-(float)O.lp+0.01)); } if(strstr(opt.c_str(),",I")) { // intervalle de fit selon X size_t p = opt.find(",I"); size_t q = opt.find_first_of(',',p+1); string dum = opt.substr(p,q-p); if(dum.length()>2) sscanf(dum.c_str(),",I%d/%d",&O.i1,&O.i2); } if(strstr(opt.c_str(),",J")) { // intervalle de fit selon Y size_t p = opt.find(",J"); size_t q = opt.find_first_of(',',p+1); string dum = opt.substr(p,q-p); if(dum.length()>2) sscanf(dum.c_str(),",J%d/%d",&O.j1,&O.j2); } return; } // ---------------- Fenetre de fit interactive ------- /* --Methode-- */ PIAFitterWind::PIAFitterWind(PIStdImgApp* par, PIAFitter* fiter) : PIWindow((PIMsgHandler*)par, "PIAFitter", PIWK_normal, 240, 240, 150, 150) { dap = par; fitter = fiter; int bsx, bsy, spx, spy; // On definit la taille a partir de la taille par defaut des composantes // PIApplicationPrefCompSize(bsx, bsy); par->PrefCompSz(bsx, bsy); spx = bsx/10; spy = bsy/4; int wszx = 5*spx+3*bsx; int wszy = 5*bsy+6*spy; SetSize(wszx, wszy); int cpx = spx; int cpy = spy; int csx = cpx; int csy = cpy; lab[0] = new PILabel(this, "Object", 1.5*bsx, bsy, cpx, cpy); cpy += spy+bsy; lab[1] = new PILabel(this, "Params", 1.5*bsx, bsy, cpx, cpy); cpx += bsx*1.5+spx; cpy = spy; txt[0] = new PIText(this, "", 3.5*bsx, bsy, cpx, cpy); cpy += spy+bsy; txt[1] = new PIText(this, "1.", 3.5*bsx, bsy, cpx, cpy); cpy += spy+bsy; ckb[0] = new PICheckBox(this,"Gen.Func", 1001, 2.5*bsx, bsy, cpx, cpy); cpx += bsx*1.5+spx; ckb[1] = new PICheckBox(this,"Gen.Resid", 1002, 2.5*bsx, bsy, cpx, cpy); cpy += spy+bsy; pom[0] = new PIOptMenu(this, "FitFunc", 2.5*bsx, bsy, cpx, cpy); pom[0]->AppendItem("Poly0", 100); pom[0]->AppendItem("Poly1", 101); pom[0]->AppendItem("Poly2", 102); pom[0]->AppendItem("Gaussienne", 103); pom[0]->AppendItem("Gauss+Poly0",104); pom[0]->AppendItem("Gauss+Poly1",105); pom[0]->AppendItem("Gauss+Poly2",106); cpx += bsx*1.5+spx; pom[1] = new PIOptMenu(this, "Bidon", 2.5*bsx, bsy, cpx, cpy); pom[1]->AppendItem("Un", 150); pom[1]->AppendItem("Deux",250); pom[1]->AppendItem("Trois",350); cpy += spy+bsy; cpx = 0.5*spx; but[0] = new PIButton(this, "DoFit", 555, bsx*2, bsy, cpx, cpy); cpx += 3*spx; but[1] = new PIButton(this, "Dismiss", 777, bsx*2, bsy, cpx, cpy); } /* --Methode-- */ PIAFitterWind::~PIAFitterWind() { for(int i=0; i<2; i++) { delete lab[i]; delete txt[i]; delete pom[i]; delete ckb[i]; delete but[i]; } } /* --Methode-- */ void PIAFitterWind::Show() { // Si on veut initialiser des trucs au moment ou apparait la fenetre txt[0]->SetText(oname); PIWindow::Show(); } /* --Methode-- */ void PIAFitterWind::Process(PIMessage msg, PIMsgHandler* sender, void* data) { char *mf[7] = {"p0","p1","p2","g","g0","g1","g2"}; msg = UserMsg(msg); if (msg == 777) { Hide(); return; } // On cache la fenetre if (msg == 555) { // On fait le fit vector args; string cmd = oname; string a; args.push_back(oname); int imf = pom[0]->GetValue()-100; if ((imf < 0) || (imf > 6)) imf = 0; a = mf[imf]; cmd += " " + a + " "; args.push_back(a); a = txt[1]->GetText(); // Definition des parametres cmd += a; args.push_back(a); if (ckb[0]->GetState() || ckb[1]->GetState()) { a = "o:"; if (ckb[0]->GetState()) a += "f"; if (ckb[1]->GetState()) a += "r"; cmd += " " + a; args.push_back(a); } cout << "FitComm= fit " << cmd << endl; string kw = "fit"; fitter->Execute(kw, args); } }