#include #include #include #include "strutil.h" #include "perrors.h" #include "ntuple.h" #include "thsafeop.h" namespace SOPHYA { #define LENNAME 8 #define LENNAME1 (LENNAME+1) #define BADVAL -1.e19 /*! \class NTuple \ingroup HiStats Simple NTuple class (a Table or 2-D data set) with double or single precision floating point value columns. \warning Thread safe fill operation can be activated using the method SetThreadSafe() Default mode is NON thread-safe fill. \sa SOPHYA::ObjFileIO \code #include "ntuple.h" // ... const char * names[3] = {"XPos", "YPos", "Val"}; // NTuple (Table) creation with 3 columns (double precision) NTuple nt(3, names); // Filling the NTuple r_8 x[3]; for(int i=0; i<63; i++) { x[0] = (i%9)-4.; x[1] = (i/9)-3.; x[2] = x[0]*x[0]+x[1]*x[1]; nt.Fill(x); } // Printing table info cout << nt ; // Saving object into a PPF file POutPersist po("nt.ppf"); po << nt ; \endcode */ //++ // Class NTuple // Lib Outils++ // include ntuple.h // // Classe de ntuples //-- //++ // Links Parents // PPersist // NTupleInterface //-- /* --Methode-- */ //! Default constructor - To be used when reading in an NTuple. //++ NTuple::NTuple() // // Createur par defaut //-- { mNVar = mNEnt = mBlk = mNBlk = 0; mVar = NULL; mVarD = NULL; mFgDouble = true; mInfo = NULL; mThS = NULL; } //! Constructor with specification of number of columns and column names /*! \param nvar : Number of columns in the table \param noms : Array of column names \param blk : Optional argument specifying number of table lines in a given data block \param fgdouble : if \b true: internal data kept as double precision values (r_8), simple precision (r_4) otherwise */ //++ NTuple::NTuple(int nvar, char** noms, int blk, bool fgdouble) // // Createur d'un ntuple de `nvar' variables dont les // noms sont dans le tableau de chaines de caracteres `noms' // avec `blk' d'evenements par blocks. //-- { if (nvar <= 0) throw ParmError("NTuple::NTuple(nvar<=0) with char** noms"); Initialize(nvar,blk,fgdouble); for(int i=0; i& noms, int blk, bool fgdouble) { int nvar = noms.size(); if (nvar <= 0) throw ParmError("NTuple::NTuple(nvar<=0) with vector& noms"); Initialize(nvar,blk,fgdouble); for(int i=0; i 0) for(i=0;i0) { if (mFgDouble) for(i=0; i 0) for(i=0;ilock(); // Thread-safe operation int numb = mNEnt/mBlk; if (numb >= mNBlk) { if (mFgDouble) { r_8* pt = new r_8[mNVar*mBlk]; mNBlk++; mPtrD.push_back(pt); } else { r_4* pt = new r_4[mNVar*mBlk]; mNBlk++; mPtr.push_back(pt); } } int offb = mNEnt-numb*mBlk; if (mFgDouble) for(int i=0; iunlock(); // Thread-safe operation return; } /* --Methode-- */ //! Adds an entry (a line) to the table (double precision) /*! \param x : content of the line to be appended to the table */ //++ void NTuple::Fill(r_8* x) // // Remplit le ntuple avec le tableau double precision `x'. //-- { if (mThS) mThS->lock(); // Thread-safe operation int numb = mNEnt/mBlk; if (numb >= mNBlk) { if (mFgDouble) { r_8* pt = new r_8[mNVar*mBlk]; mNBlk++; mPtrD.push_back(pt); } else { r_4* pt = new r_4[mNVar*mBlk]; mNBlk++; mPtr.push_back(pt); } } int offb = mNEnt-numb*mBlk; if (mFgDouble) memcpy((mPtrD[numb]+offb*mNVar), x, mNVar*sizeof(r_8)); else for(int i=0; iunlock(); // Thread-safe operation return; } /* --Methode-- */ //++ float NTuple::GetVal(int n, int k) const // // Retourne la valeur de la variable `k' de l'evenement `n'. //-- { if (n >= mNEnt) return(BADVAL); if ( (k < 0) || (k >= mNVar) ) return(BADVAL); int numb = n/mBlk; int offb = n-numb*mBlk; if ( mFgDouble) return(*(mPtrD[numb]+offb*mNVar+k)); else return(*(mPtr[numb]+offb*mNVar+k)); } /* --Methode-- */ //++ int NTuple::IndexNom(const char* nom) const // // Retourne le numero de la variable de nom `nom'. //-- { int i; string snom = nom; for(i=0; i= 0) && (k < mNVar)) strncpy(nomretour, mNames[k].c_str(), 255); return(nomretour); } /* --Methode-- */ //++ r_4* NTuple::GetVec(int n, r_4* ret) const // // Retourne l'evenement `n' dans le vecteur `ret'. //-- { int i; if (ret == NULL) ret = mVar; if (n >= mNEnt) { for(i=0; i= mNEnt) { for(i=0; i mNEnt) nmax = mNEnt; for(i=num; i= 0) { if (posb < 0) posb = postab; else if (postab < posb) posb = postab; } if (posb >= 0) ccp[posb] = '\0'; if ( isdigit(line[0]) || (line[0] == '+') || (line[0] == '-') || (line[0] == '.') ) xv[kk] = atof(ccp); if (posb < 0) break; ccp += posb+1; j = 0; while ( (ccp[j] != '\0') && ((ccp[j] == ' ') || (ccp[j] == '\t')) ) j++; ccp += j; } Fill(xv); nlread++; } delete[] xv; cout << "NTuple::FillFromASCIIFile( " << fn << ") " << nlread << " fill from file " << endl; return(nlread); } // ------- Implementation de l interface NTuple --------- /* --Methode-- */ sa_size_t NTuple::NbLines() const { return(NEntry()); } /* --Methode-- */ sa_size_t NTuple::NbColumns() const { return(NVar()); } /* --Methode-- */ r_8 * NTuple::GetLineD(sa_size_t n) const { return(GetVecD(n)); } /* --Methode-- */ r_8 NTuple::GetCell(sa_size_t n, sa_size_t k) const { return(GetVal(n, k)); } /* --Methode-- */ r_8 NTuple::GetCell(sa_size_t n, string const & nom) const { return(GetVal(n, nom.c_str())); } /* --Methode-- */ //++ void NTuple::GetMinMax(sa_size_t k, double& min, double& max) const // // Retourne le minimum et le maximum de la variable `k'. //-- { min = 9.e19; max = -9.e19; if ( (k < 0) || (k >= mNVar) ) return; int jb,ib,i; double x; i=0; for(jb=0; jb< mNBlk; jb++) for(ib=0; ib< mBlk; ib++) { if (i >= mNEnt) break; i++; x = (mFgDouble) ? *(mPtrD[jb]+ib*mNVar+k) : *(mPtr[jb]+ib*mNVar+k); if(i==1) {min = x; max = x;} if (x < min) min = x; if (x > max) max = x; } return; } /* --Methode-- */ void NTuple::GetMinMax(string const & nom, double& min, double& max) const { GetMinMax(IndexNom(nom.c_str()), min, max); } /* --Methode-- */ sa_size_t NTuple::ColumnIndex(string const & nom) const { return(IndexNom(nom.c_str())); } /* --Methode-- */ string NTuple::ColumnName(sa_size_t k) const { return(NomIndex(k)); } /* --Methode-- */ //++ string NTuple::VarList_C(const char* nomx) const // // Retourne une chaine de caracteres avec la declaration des noms de // variables. si "nomx!=NULL" , des instructions d'affectation // a partir d'un tableau "nomx[i]" sont ajoutees. //-- { string rets=""; int i; for(i=0; i 0) ) rets += ";"; if (i%5 == 0) rets += "\ndouble "; else rets += ","; rets += mNames[i]; } rets += "; \n"; if (nomx) { char buff[256]; for(i=0; i 0) ) rets += "\n"; } } return(rets); } /* --Methode-- */ //++ string NTuple::LineHeaderToString() const // Retourne une chaine de caracteres avec la liste des noms de // variables, utilisables pour une impression //-- { char buff[32]; string rets=" Num "; for(int i=0; i \ingroup HiStats Persistence (serialisation) handler for class NTuple */ /* --Methode-- */ //++ DECL_TEMP_SPEC /* equivalent a template <> , pour SGI-CC en particulier */ void ObjFileIO::WriteSelf(POutPersist& s) const // // Ecriture ppersist du ntuple. //-- { if (dobj == NULL) return; // On ecrit cette chaine pour compatibilite avec les anciennes version (1,2) string strg = "NTuple"; s.Put(strg); // On ecrit 3 uint_4 .... // [0]: Numero de version ; // [1] : bit1 non nul -> has info, bit 2 non nul mFgDouble=true // [2] : reserve uint_4 itab[3]; itab[0] = 3; // Numero de version a 3 itab[1] = itab[2] = 0; if (dobj->mInfo) itab[1] = 1; if (dobj->mFgDouble) itab[1] += 2; s.Put(itab, 3); s.Put(dobj->mNVar); for(int k=0; kmNVar; k++) s.Put(dobj->mNames[k]); s.Put(dobj->mNEnt); s.Put(dobj->mBlk); s.Put(dobj->mNBlk); if (dobj->mInfo) s << (*(dobj->mInfo)); int jb; if (dobj->mFgDouble) for(jb=0; jbmNBlk; jb++) s.Put(dobj->mPtrD[jb], dobj->mNVar*dobj->mBlk); else for(jb=0; jbmNBlk; jb++) s.Put(dobj->mPtr[jb], dobj->mNVar*dobj->mBlk); return; } /* --Methode-- */ //++ DECL_TEMP_SPEC /* equivalent a template <> , pour SGI-CC en particulier */ void ObjFileIO::ReadSelf(PInPersist& s) // // Lecture ppersist du ntuple. //-- { if (dobj == NULL) dobj = new NTuple; else dobj->Clean(); bool hadinfo = false; string strg; s.Get(strg); uint_4 itab[3] = {0,0,0}; if (strg == "NTuple") { s.Get(itab, 3); if ( ((itab[0] < 3) && (itab[1] != 0)) || ((itab[0] >= 3) && ((itab[1]&1) == 1)) ) hadinfo = true; } else { // Ancienne version de PPF NTuple - Pour savoir s'il y avait un DVList Info associe char buff[256]; strcpy(buff, strg.c_str()); if (strncmp(buff+strlen(buff)-7, "HasInfo", 7) == 0) hadinfo = true; } if (itab[0] < 3) { // Lecture version anterieures V= 1 , 2 s.Get(dobj->mNVar); dobj->mVar = new r_4[dobj->mNVar]; dobj->mVarD = new r_8[dobj->mNVar]; char * names = new char[dobj->mNVar*LENNAME1]; s.GetBytes(names, dobj->mNVar*LENNAME1); for(int k=0; kmNVar; k++) dobj->mNames.push_back(names+k*LENNAME1); s.Get(dobj->mNEnt); s.Get(dobj->mBlk); s.Get(dobj->mNBlk); if (hadinfo) { // Lecture eventuelle du DVList Info if (dobj->mInfo == NULL) dobj->mInfo = new DVList; s >> (*(dobj->mInfo)); } // Il n'y avait que des NTuple avec data float pour V < 3 dobj->mFgDouble = false; int jb; for(jb=0; jbmNBlk; jb++) { r_4* pt = new r_4[dobj->mNVar*dobj->mBlk]; dobj->mPtr.push_back(pt); s.Get(dobj->mPtr[jb], dobj->mNVar*dobj->mBlk); } } else { // Lecture version V 3 s.Get(dobj->mNVar); dobj->mVar = new r_4[dobj->mNVar]; dobj->mVarD = new r_8[dobj->mNVar]; string nom; for(int k=0; kmNVar; k++) { s.Get(nom); dobj->mNames.push_back(nom); } s.Get(dobj->mNEnt); s.Get(dobj->mBlk); s.Get(dobj->mNBlk); if (hadinfo) { // Lecture eventuelle du DVList Info if (dobj->mInfo == NULL) dobj->mInfo = new DVList; s >> (*(dobj->mInfo)); } // Il n'y avait que des NTuple avec data float pour V < 3 dobj->mFgDouble = ((itab[1]&2) == 2) ? true : false; int jb; if (dobj->mFgDouble) { for(jb=0; jbmNBlk; jb++) { r_8* pt = new r_8[dobj->mNVar*dobj->mBlk]; dobj->mPtrD.push_back(pt); s.Get(dobj->mPtrD[jb], dobj->mNVar*dobj->mBlk); } } else { for(jb=0; jbmNBlk; jb++) { r_4* pt = new r_4[dobj->mNVar*dobj->mBlk]; dobj->mPtr.push_back(pt); s.Get(dobj->mPtr[jb], dobj->mNVar*dobj->mBlk); } } } // Fin lecture V3 } #ifdef __CXX_PRAGMA_TEMPLATES__ #pragma define_template ObjFileIO #endif #if defined(ANSI_TEMPLATES) || defined(GNU_TEMPLATES) template class ObjFileIO; #endif } // FIN namespace SOPHYA