#include "sopnamsp.h" #include "machdefs.h" #include #include #include #ifndef NO_VALUES_H #include #endif #include #include #include #include "strutil.h" #include "nbtri.h" #include "generalfit.h" #include "generaldata.h" #include "pexceptions.h" #include "objfio.h" //================================================================ // GeneralFitData //================================================================ /*! \class SOPHYA::GeneralFitData \ingroup NTools Classe de stoquage de donnees a plusieurs variables avec erreur sur l'ordonnee et sur les abscisses (options) : \f$ {x0(i),Ex0(i), x1(i),Ex1(i), x2(i),Ex2(i) ... ; Y(i),EY(i)} \f$ \verbatim Pour memoire, structure du rangement (n=mNVar): - Valeur des abscisses mXP (idem pour mErrXP): x0,x1,x2,...,xn x0,x1,x2,...,xn .... x0,x1,x2,....,xn | 1er point | | 2sd point | .... | point mNData | Donc abscisse J=[0,mNVar[ du point numero I=[0,mNData[: mXP[I*mNVar+J] - Valeur de l'ordonnee mF (idem pour mErr et mOK): f f f | 1er point | | 2sd point | .... | point mNData | Donc point numero I [0,mNData[ : mF[i] \endverbatim */ ////////////////////////////////////////////////////////////////////// /*! Constructeur. ``nVar'' represente la dimension de l'espace des abscisses, ``ndatalloc'' le nombre maximum de points et ``errx'' si non nul indique que l'on fournit des erreurs sur les ``nVar'' variables en abscisse. */ GeneralFitData::GeneralFitData(unsigned int nVar, unsigned int ndatalloc, uint_2 errx) : mNVar(0), mNDataAlloc(0), mNData(0), mNDataGood(0), mOk_EXP(0) , mXP(NULL), mErrXP(NULL), mF(NULL), mErr(NULL), mOK(NULL) , BuffVar(NULL), BuffVarR4(NULL) { try { Alloc(nVar,ndatalloc,errx); } catch(PException e) { cout << "Exception : " << typeid(e).name() << " " << e.Msg() << endl; throw; } } /*! Constructeur par copie. Si ``clean'' est ``true'' seules les donnees valides de ``data'' sont copiees. Si ``clean'' est ``false'' (defaut) toutes les donnees sont copiees et la taille totale de ``data'' est allouee meme si elle est plus grande que la taille des donnees stoquees. */ GeneralFitData::GeneralFitData(const GeneralFitData& data, bool clean) : mNVar(0), mNDataAlloc(0), mNData(0), mNDataGood(0), mOk_EXP(0) , mXP(NULL), mErrXP(NULL), mF(NULL), mErr(NULL), mOK(NULL) , BuffVar(NULL), BuffVarR4(NULL) { try { Alloc(data.mNVar,((clean)?data.mNDataGood:data.mNDataAlloc),((data.mErrXP)?1:0)); } catch(PException e) { cout << "Exception : " << typeid(e).name() << " " << e.Msg() << endl; throw; } // Remplissage if(data.mNData>0) { r_8* ret; for(int i=0;i0 && ndatalloc>0 ); Delete(); if(errx>=0) mOk_EXP = (uint_2) errx; mNVar = nVar; mNDataAlloc = ndatalloc; try { mXP = new r_8[nVar*ndatalloc]; if(mOk_EXP) mErrXP = new r_8[nVar*ndatalloc]; mF = new r_8[ndatalloc]; mErr = new r_8[ndatalloc]; mOK = new uint_2[ndatalloc]; BuffVar = new r_8[2*nVar+3]; BuffVarR4 = (r_4 *) BuffVar; } catch(PException e) { throw(AllocationError("GeneralFitData::Alloc allocation error\n")); } } ////////////////////////////////////////////////////////////////////// /*! Gestion des des-allocations */ void GeneralFitData::Delete() { mNVar = mNDataAlloc = mNData = mNDataGood = 0; if( mXP != NULL ) {delete [] mXP; mXP = NULL;} if( mErrXP != NULL ) {delete [] mErrXP; mErrXP = NULL;} if( mF != NULL ) {delete [] mF; mF = NULL;} if( mErr != NULL ) {delete [] mErr; mErr = NULL;} if( mOK != NULL ) {delete [] mOK; mOK = NULL;} if( BuffVar != NULL ) {delete [] BuffVar; BuffVar = NULL; BuffVarR4 = NULL;} } ////////////////////////////////////////////////////////////////////// /*! Remise a zero de la structure pour nouveau remplissage (pas d'arg) ou remise a la position ``ptr'' (si arg). Les donnees apres ``ptr'' sont sur-ecrites. */ void GeneralFitData::SetDataPtr(int ptr) { ASSERT(ptr >= 0 && ptr < mNDataAlloc); mNData = ptr; mNDataGood = 0; if(ptr==0) return; for(int i=0;i= 0 && i < mNData); if( ! mOK[i] ) return; mOK[i] = 0; mNDataGood--; } /*! Pour tuer une serie de points */ void GeneralFitData::KillData(int i1,int i2) { ASSERT(i1 >= 0 && i1 < mNData); ASSERT(i2 >= 0 && i2 < mNData); ASSERT(i1 <= i2 ); for(int i=i1;i<=i2;i++) KillData(i); } ////////////////////////////////////////////////////////////////////// /*! Pour re-valider le point numero i ([0,NData]). */ void GeneralFitData::ValidData(int i) { ASSERT(i >= 0 && i < mNData); if( mOK[i] ) return; if( mErr[i]<=0. ) return; if(mOk_EXP) { for(int j=0;j= 0 && i1 < mNData); ASSERT(i2 >= 0 && i2 < mNData); ASSERT(i1 <= i2 ); for(int i=i1;i<=i2;i++) ValidData(i); } /*! Pour re-valider tous les points. */ void GeneralFitData::ValidData() { for(int i=0;i=0 && i0 && mNData+nData<=mNDataAlloc); for(int i=0;i0 && mNData+nData<=mNDataAlloc); for(int i=0;i0 && mNData+nData<=mNDataAlloc); for(int i=0;i0 && mNData+nData<=mNDataAlloc); for(int i=0;i0 && mNData+nData<=mNDataAlloc); if(mOk_EXP && !errxp) {for(int j=0;j0 && mNData+nData<=mNDataAlloc); if(mOk_EXP && !errxp) {for(int j=0;j=mNData) i1 = mNData-1; if(i2>=mNData) i2 = mNData-1; if(i1>i2) i2 = mNData-1; cout<<"GeneralFitData::PrintData[NData=" <0); PrintData(0,mNData-1); } /*! Impression de l'etat de la structure de donnees avec bornes sur "s" */ void GeneralFitData::Show(ostream& os) const { double min,max; os<<"GeneralFitData:: NVar,ErrX="<3) return -1; if(var>=2 && (ix<0 || ix>=mNVar) ) return -1; double min=1., max=-1.; int ntest = 0; for(int i=0;imax) {max = v; imax = i;} ntest++; } return ntest; } /*! Retourne le minimum et le maximum de la variable ``var'' (cf commentaires GetMnMx). */ int GeneralFitData::GetMnMx(int var,double& min,double& max) const { min = 1.; max = -1.; int imin,imax; int ntest = GetMnMx(var,imin,imax); if(ntest<=0) return ntest; int ix = var/10; var = var%10; if(var==0) { if(imin>=0) min = Val(imin); if(imax>=0) max = Val(imax); } else if(var==1) { if(imin>=0) min = EVal(imin); if(imax>=0) max = EVal(imax); } else if(var==2) { if(imin>=0) min = Absc(ix,imin); if(imax>=0) max = Absc(ix,imax); } else if(var==3) { if(imin>=0) min = EAbsc(ix,imin); if(imax>=0) max = EAbsc(ix,imax); } return ntest; } ////////////////////////////////////////////////////////////////////// /*! // Retourne la moyenne et le sigma de la variable ``var'' (cf commentaires GetMnMx). \verbatim - Return : nombre de donnees utilisees, -1 si pb, -2 si sigma<0. - Seuls les points valides de valeur entre min,max sont utilises. Si min>=max pas de coupures sur les valeurs. \endverbatim */ int GeneralFitData::GetMeanSigma(int var,double& mean,double& sigma,double min,double max) const { mean = sigma = 0.; int ix = var/10; var = var%10; if(var<0 || var>3) return -1; if(var>=2 && (ix<0 || ix>=mNVar) ) return -1; int ntest = 0; for(int i=0;i0.) sigma = sqrt(sigma); } return ntest; } /*! Retourne le mode de la variable ``var'' (cf commentaires GetMnMx). \verbatim - Return : nombre de donnees utilisees, -1 si pb. - Seuls les points valides de valeur entre min,max sont utilises. Si min>=max pas de coupures sur les valeurs. - Le calcul du mode est approximee par la formule: Mode = Median - coeff*(Mean-Median) (def: coeff=0.8) - Kendall and Stuart donne coeff=2., mais coeff peut etre regle. \endverbatim */ int GeneralFitData::GetMoMeMed(int var,double& mode,double& mean,double& median, double min,double max,double coeff) const { mode = mean = median = 0.; if(mNData<=0) return -1; int ix = var/10; var = var%10; if(var<0 || var>3) return -1; if(var>=2 && (ix<0 || ix>=mNVar) ) return -1; double* buff = new double[mNData]; int ntest = 0; for(int i=0;i=mNVar) return -2.; if(mNDataGood<=0) return -4.; TVector x(mNDataGood); TVector y(mNDataGood); TVector ey2(1); if(ey) ey2.Realloc(mNDataGood,true); int ntest = 0; for(int i=0;i=mNDataGood) return -5.; x(ntest) = Absc(varx,i) - xc; y(ntest) = Val(i); if(ey) ey2(ntest) = EVal(i)*EVal(i); ntest++; } double res = 0.; if(ey) { TVector errcoef(1); res = pol.Fit(x,y,ey2,degre,errcoef); } else { res = pol.Fit(x,y,degre); } return res; } /*! Pour fiter un polynome de degre ``degre1''. On fite Z=f(X-xc,Y-yc) ou Z=Val et X=Absc(varx) et Y=Absc(vary). Si ``ey'' est ``true'' le fit prend en compte les erreurs stoquees dans EVal, sinon fit sans erreurs. Si ``degre2'' negatif, le fit determine un polynome en X,Y de degre total ``degre`''. Si ``degre2'' positif ou nul, le fit demande un fit de ``degre1'' pour la variable X et de degre ``degre2'' sur la variable Y. Le resultat du fit est retourne dans le polynome ``pol''. On re-centre les abscisses X de ``xc'' et Y de ``yc''. \verbatim Return: - Res = le residu du fit - -1 si degre<0 - -2 si probleme sur numero de variable X - -3 si probleme sur numero de variable Y - -4 si NDataGood<0 - -5 si nombre de data trouves different de NDataGood \endverbatim */ double GeneralFitData::PolFit(int varx,int vary,Poly2& pol,int degre1,int degre2,bool ez ,double xc,double yc) const { if(degre1<0) return -1.; if(varx<0 || varx>=mNVar) return -2.; if(vary<0 || vary>=mNVar || vary==varx) return -3.; if(mNDataGood<=0) return -4.; TVector x(mNDataGood); TVector y(mNDataGood); TVector z(mNDataGood); TVector ez2(1); if(ez) ez2.Realloc(mNDataGood,true); int ntest = 0; for(int i=0;i=mNDataGood) return -5.; x(ntest) = Absc(varx,i) - xc; y(ntest) = Absc(vary,i) - yc; z(ntest) = Val(i); if(ez) ez2(ntest) = EVal(i)*EVal(i); ntest++; } double res = 0.; if(ez) { TVector errcoef(1); if(degre2>0) res = pol.Fit(x,y,z,ez2,degre1,degre2,errcoef); else res = pol.Fit(x,y,z,ez2,degre1,errcoef); } else { if(degre2>0) res = pol.Fit(x,y,z,degre1,degre2); else res = pol.Fit(x,y,z,degre1); } return res; } ////////////////////////////////////////////////////////////////////// /*! Retourne une classe contenant les residus du fit ``gfit''. */ GeneralFitData GeneralFitData::FitResidus(GeneralFit& gfit) const { if(gfit.GetNVar()!=mNVar) throw(SzMismatchError("GeneralFitData::FitResidus: size mismatch\n")); return gfit.DataResidus(true); } /*! Retourne une classe contenant la function du fit ``gfit''. */ GeneralFitData GeneralFitData::FitFunction(GeneralFit& gfit) const { if(gfit.GetNVar()!=mNVar) throw(SzMismatchError("GeneralFitData::FitFunction: size mismatch\n")); return gfit.DataFunction(true); } ////////////////////////////////////////////////////////////////////// /*! // Retourne la donnee `n' dans le vecteur de double `ret'. \verbatim Par defaut, ret=NULL et le buffer interne de la classe est retourne - Les donnees sont rangees dans l'ordre: x0,x1,x2,... ; ex0,ex1,ex2,... ; y ; ey ; ok(0/1) |<- NVar ->| + |<- NVar ->| + 1 + 1 + 1 Le vecteur ret a la taille 2*NVar+2+1 \endverbatim */ r_8* GeneralFitData::GetVec(int n, r_8* ret) const { int i; if (ret == NULL) ret = BuffVar; for(i=0; i<2*mNVar+3; i++) ret[i] = 0.; if (n >= mNData) return(ret); memcpy(ret, mXP+n*mNVar, mNVar*sizeof(r_8)); if(mErrXP) memcpy(ret+mNVar, mErrXP+n*mNVar, mNVar*sizeof(r_8)); ret[2*mNVar] = mF[n]; ret[2*mNVar+1] = mErr[n]; ret[2*mNVar+2] = (double) mOK[n]; return(ret); } /*! Retourne la donnee `n' dans le vecteur de float `ret' (meme commentaires que pour GetVec). */ r_4* GeneralFitData::GetVecR4(int n, r_4* ret) const { if (ret == NULL) ret = BuffVarR4; double *buff = new double[2*mNVar+3]; GetVec(n,buff); for(int i=0;i<2*mNVar+3;i++) ret[i] = (float) buff[i]; delete [] buff; return ret; } ////////////////////////////////////////////////////////////////////// // ------- Implementation de l interface NTuple --------- /*! Retourne le nombre de ligne = NData() (pour interface NTuple) */ sa_size_t GeneralFitData::NbLines() const { return(NData()); } /*! Retourne le nombre de colonnes du ntuple equivalent: \verbatim Exemple: on a une fonction sur un espace a 4 dimensions: "x0,x1,x2,x3 , ex0,ex1,ex2,ex3 , y, ey , ok" 0 1 2 3 4 5 6 7 8 9 10 | | | | | | | 0 nv-1 nv 2*nv-1 2*nv 2*nv+1 2*nv+2 soit 2*nvar+3 variables/colonnes. \endverbatim (pour interface NTuple) */ sa_size_t GeneralFitData::NbColumns() const { return(2*NVar()+3); } //! Pour interface NTuple r_8 * GeneralFitData::GetLineD(sa_size_t n) const { return(GetVec(n,NULL)); } //! Pour interface NTuple r_8 GeneralFitData::GetCell(sa_size_t n, sa_size_t k) const { if(k<0 || k>=2*NVar()+3) return 0.; r_8 * val = GetVec(n,NULL); return val[k]; } //! Pour interface NTuple r_8 GeneralFitData::GetCell(sa_size_t n, string const & nom) const { sa_size_t k = ColumnIndex(nom); return(GetCell(n,k)); } /*! Retourne le minimum et le maximum de la variable `k' (pour interface NTuple). */ void GeneralFitData::GetMinMax(sa_size_t k, double& min, double& max) const { int var; if(k<0 || k>=2*NVar()+3) return; else if(k=2*NVar()+3) return string(""); char str[64] = ""; if(k=0 if errtmp>0 return max(errtmp,errmin) if errtmp<=0 return errtmp errmin <0 if errtmp>0 return max(errtmp,|errmin|) if errtmp<=0 return |errmin| \endverbatim */ double GeneralFitData::ComputeError(double val,double err,FitErrType errtype ,double errscale,double errmin,bool nozero) { bool errminneg=false; if(errmin<0.) {errminneg=true; errmin*=-1.;} if(errscale<0.) errscale=1.; // Choix du type d'erreur if(errtype==ConstantError) err = errscale; else if(errtype==SqrtError) err = errscale*sqrt(fabs(val)); else if(errtype==ProporError) err = errscale*fabs(val); // Gestion du minimum a partir de la valeur calculee precedemment "err" // Ex1: errmin=1., err=10. ==> 10. // err=0.5 ==> 1. // err=0. ==> 0. // err=-2. ==> -2. // Ex2: errmin=-1., err=10. ==> 10. // err=0.5 ==> 1. // err=0. ==> 1. // err=-2. ==> 11. if(err>0.) err = (err>errmin) ? err: errmin; else if(errminneg) err = errmin; // ne pas retourner d'erreurs negatives si demande if(nozero && err<0.) err=0.; return err; } /////////////////////////////////////////////////////////// // -------------------------------------------------------- // Les objets delegues pour la gestion de persistance // -------------------------------------------------------- /////////////////////////////////////////////////////////// DECL_TEMP_SPEC /* equivalent a template <> , pour SGI-CC en particulier */ void ObjFileIO::ReadSelf(PInPersist& is) { char strg[256]; if(dobj==NULL) dobj=new GeneralFitData; else dobj->Delete(); // Lecture entete is.GetLine(strg, 255); // Ecriture des valeurs de definitions int_4 nvar,ndatalloc,ndata,ndatagood; is.Get(nvar); is.Get(ndatalloc); is.Get(ndata); is.Get(ndatagood); is.Get(dobj->mOk_EXP); if(nvar<=0 || ndatalloc<=0 || ndata<=0 || ndatagood<0 || ndatallocAlloc(nvar,ndatalloc,-1); dobj->mNData = ndata; dobj->mNDataGood = ndatagood; // Lecture des datas is.GetLine(strg, 255); int blen = dobj->mNVar + 3; if(dobj->mOk_EXP) blen += dobj->mNVar; double *buff = new double[blen]; for(int i=0;imNData;i++) { is.Get(buff, blen); int ip = i*dobj->mNVar; {for(int j=0;jmNVar;j++) dobj->mXP[ip+j] = buff[j];} dobj->mF[i] = buff[dobj->mNVar]; dobj->mErr[i] = buff[dobj->mNVar+1]; dobj->mOK[i] = (uint_2)(buff[dobj->mNVar+2]+0.01); if(dobj->mOk_EXP) {for(int j=0;jmNVar;j++) dobj->mErrXP[ip+j] = buff[dobj->mNVar+3+j];} } delete [] buff; return; } DECL_TEMP_SPEC /* equivalent a template <> , pour SGI-CC en particulier */ void ObjFileIO::WriteSelf(POutPersist& os) const { if (dobj == NULL) return; char strg[256]; // Ecriture entete pour identifier facilement sprintf(strg,"GeneralFitData: NVar=%d NDataAlloc=%d NData=%d NDataGood=%d Ok_EXP=%d" ,dobj->mNVar,dobj->mNDataAlloc,dobj->mNData,dobj->mNDataGood,dobj->mOk_EXP); os.PutLine(strg); // Ecriture des valeurs de definitions os.Put(dobj->mNVar); os.Put(dobj->mNDataAlloc); os.Put(dobj->mNData); os.Put(dobj->mNDataGood); os.Put(dobj->mOk_EXP); if(dobj->mNVar<=0 || dobj->mNDataAlloc<=0 || dobj->mNData<=0 || dobj->mNDataGood<0) return; // Ecriture des datas (on n'ecrit que mNData / mNDataAlloc) sprintf(strg ,"GeneralFitData: Abscisses, Ordonnee, Erreur Ordonnee, Flag, Erreur Abscisses"); os.PutLine(strg); int blen = dobj->mNVar + 3; if(dobj->mOk_EXP) blen += dobj->mNVar; double *buff = new double[blen]; for(int i=0;imNData;i++) { {for(int j=0;jmNVar;j++) buff[j] = dobj->Absc(j,i);} buff[dobj->mNVar] = dobj->Val(i); buff[dobj->mNVar+1] = dobj->EVal(i); buff[dobj->mNVar+2] = (double) dobj->IsValid(i); if(dobj->mOk_EXP) {for(int j=0;jmNVar;j++) buff[dobj->mNVar+3+j] = dobj->EAbsc(j,i);} os.Put(buff, blen); } delete [] buff; return; } #ifdef __CXX_PRAGMA_TEMPLATES__ #pragma define_template ObjFileIO #endif #if defined(ANSI_TEMPLATES) || defined(GNU_TEMPLATES) template class SOPHYA::ObjFileIO; #endif