Index: trunk/SophyaLib/NTools/ntuple.cc
===================================================================
--- trunk/SophyaLib/NTools/ntuple.cc	(revision 475)
+++ trunk/SophyaLib/NTools/ntuple.cc	(revision 490)
@@ -2,4 +2,5 @@
 #include <string.h>
 
+#include "strutil.h"
 #include "perrors.h"
 #include "ntuple.h"
@@ -16,4 +17,9 @@
 //
 //	Classe de ntuples
+//--
+//++
+// Links        Parents
+// PPersist
+// NTupleInterface
 //--
 
@@ -35,33 +41,61 @@
 //++
 NTuple::NTuple(int nvar, char** noms, int blk)
-  //
-  //	Createur d'un ntuple de `nvar' variables dont les
-  //	noms sont dans le tableau de cahines de caracteres `noms'
-  //	avec `blk' d'evenements par blocks.
-//--
-{
-  mNVar = mNEnt = mBlk = mNBlk = 0;
-  mVar = NULL;
-  mVarD = NULL;
-  mNames = NULL;
-  mInfo = NULL;
-  if (nvar <= 0)  THROW(sizeMismatchErr); 
-  mNVar = nvar;
-  mVar = new r_4[nvar];
-  mVarD = new r_8[nvar];
-  if (blk < 10) blk = 10;
-  mBlk = blk;
-  // On prend des noms de LENNAME char pour le moment
-  mNames = new char[nvar*LENNAME1];
-  r_4* pt = new r_4[nvar*blk];
-  mNBlk = 1;
-  mPtr.push_back(pt);
-  int i;
-  for(i=0; i<nvar; i++)
-    { 
-      strncpy(mNames+i*LENNAME1, noms[i], LENNAME);  
-      mNames[i*LENNAME1+LENNAME] = '\0'; 
-    }
-  return;
+//
+//	Createur d'un ntuple de `nvar' variables dont les
+//	noms sont dans le tableau de cahines de caracteres `noms'
+//	avec `blk' d'evenements par blocks.
+//--
+{
+mNVar = mNEnt = mBlk = mNBlk = 0;
+mVar = NULL;
+mVarD = NULL;
+mNames = NULL;
+mInfo = NULL;
+if (nvar <= 0)  THROW(sizeMismatchErr); 
+mNVar = nvar;
+mVar = new r_4[nvar];
+mVarD = new r_8[nvar];
+if (blk < 10) blk = 10;
+mBlk = blk;
+// On prend des noms de LENNAME char pour le moment
+mNames = new char[nvar*LENNAME1];
+r_4* pt = new r_4[nvar*blk];
+mNBlk = 1;
+mPtr.push_back(pt);
+int i;
+for(i=0; i<nvar; i++)
+  { strncpy(mNames+i*LENNAME1, noms[i], LENNAME);  
+  mNames[i*LENNAME1+LENNAME] = '\0'; }
+return;
+}
+
+//                                       cmv 8/10/99
+//++
+NTuple::NTuple(const NTuple& NT)
+//
+//	Createur par copie (clone).
+//--
+: mNVar(0), mNEnt(0), mBlk(0), mNBlk(0)
+, mVar(NULL), mVarD(NULL), mNames(NULL), mInfo(NULL)
+{
+if(NT.mNVar<=0) return; // cas ou NT est cree par defaut
+mNVar = NT.mNVar;
+mBlk = NT.mBlk;
+mVar = new r_4[NT.mNVar];
+mVarD = new r_8[NT.mNVar];
+mNames = new char[NT.mNVar*LENNAME1];
+
+int i;
+r_4* pt = new r_4[mNVar*mBlk];
+mNBlk = 1; mPtr.push_back(pt);
+
+for(i=0;i<mNVar;i++) strcpy(mNames+i*LENNAME1,NT.NomIndex(i)); 
+
+if(NT.mInfo!=NULL) {mInfo = new DVList; *mInfo = *(NT.mInfo);}
+
+if(NT.mNEnt<=0) return;
+for(i=0;i<NT.mNEnt;i++) {r_4* x=NT.GetVec(i,NULL); Fill(x);}
+
+return;
 }
 
@@ -79,5 +113,6 @@
 mInfo = NULL;
 PInPersist s(flnm);
-Read(s);
+ObjFileIO<NTuple> fiont(this);
+fiont.Read(s);
 }
 
@@ -96,5 +131,5 @@
 if (mInfo) delete mInfo;
 int i;
-for(i=0; i<mNBlk; i++)  delete[] mPtr[i];
+if(mNBlk>0) for(i=0; i<mNBlk; i++)  delete[] mPtr[i];
 mPtr.erase(mPtr.begin(), mPtr.end());
 mNVar = mNEnt = mBlk = mNBlk = 0;
@@ -102,5 +137,38 @@
 mVarD = NULL;
 mNames = NULL;
+mInfo = NULL;
 return;
+}
+
+/* --Methode--        cmv 08/10/99 */
+//++
+NTuple& NTuple::operator = (const NTuple& NT)
+//
+//	Operateur egal (clone).
+//--
+{
+if(this == &NT) return *this;
+Clean();
+if(NT.mNVar<=0) return *this; // cas ou NT est cree par defaut
+mNVar = NT.mNVar;
+mBlk = NT.mBlk;
+mVar = new r_4[NT.mNVar];
+mVarD = new r_8[NT.mNVar];
+mNames = new char[NT.mNVar*LENNAME1];
+
+int i;
+r_4* pt = new r_4[mNVar*mBlk];
+mNBlk = 1; mPtr.push_back(pt);
+
+for(i=0;i<mNVar;i++) strcpy(mNames+i*LENNAME1,NT.NomIndex(i)); 
+
+if(NT.mInfo!=NULL) {mInfo = new DVList; *mInfo = *(NT.mInfo);}
+
+if(NT.mNEnt<=0) return *this;
+for(i=0;i<NT.mNEnt;i++) {r_4* x=NT.GetVec(i,NULL); Fill(x);}
+
+// En fait il faudrait un createur par copie qui partage les donnees
+// quand l'objet est temporaire... trop complique A FAIRE !  cmv.
+return *this;
 }
 
@@ -167,33 +235,4 @@
 }
 
-/* --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<mNVar; i++) {
-  if ( (i%5 == 0) && (i > 0) )  rets += ";";  
-  if (i%5 == 0)   rets += "\ndouble "; 
-  else rets += ",";
-  rets += mNames+i*LENNAME1;
-  }
-rets += "; \n";
-if (nomx) { 
-  char buff[256];
-  for(i=0; i<mNVar; i++) {
-    sprintf(buff,"%s=%s[%d]; ",  mNames+i*LENNAME1, nomx, i);
-    rets += buff;
-    if ( (i%3 == 0) && (i > 0) )  rets += "\n"; 
-    }
-  }
-
-return(rets);
-}
   
 /* --Methode-- */
@@ -231,7 +270,164 @@
 }
 
-/* --Methode-- */
-//++
-void  NTuple::GetMinMax(int k, float& min, float& max)  const
+
+
+/* --Methode-- */
+//++
+DVList&  NTuple::Info()
+//
+//	Renvoie une référence sur l'objet DVList Associé
+//--
+{
+if (mInfo == NULL)  mInfo = new DVList;
+return(*mInfo);
+}
+
+/* --Methode-- */
+//++
+void  NTuple::Print(int num, int nmax)  const
+//
+//	Imprime `nmax' evenements a partir du numero `num'.
+//--
+{
+int i,j;
+
+printf("Num     ");
+for(i=0; i<mNVar; i++)  printf("%8s ", mNames+i*LENNAME1);
+putchar('\n');
+
+if (nmax <= 0)  nmax = 1;
+if (num < 0)  num = 0;
+nmax += num;
+if (nmax > mNEnt) nmax = mNEnt;
+for(i=num; i<nmax; i++) {
+  GetVec(i, NULL); 
+  printf("%6d  ", i);  
+  for(j=0; j<mNVar; j++)  printf("%8g ", (float)mVar[j]);
+  putchar('\n');
+}
+return;
+}
+
+/* --Methode-- */
+//++
+void  NTuple::Show(ostream& os)  const
+//
+//	Imprime l'information generale sur le ntuple.
+//--
+{
+os << "NTuple: NVar= " << mNVar << " NEnt=" << mNEnt  
+   << " (Blk Sz,Nb= " << mBlk << " ," << mNBlk << ")\n";
+os << "            Variables       Min      Max       \n";
+int i;
+double min, max;
+char buff[128];
+for(i=0; i<mNVar; i++) {
+  GetMinMax(i, min, max);
+  sprintf(buff, "%3d  %16s  %10lg  %10lg \n", i, mNames+i*LENNAME1, min, max);
+  os << (string)buff ;
+  }
+os << endl;
+}
+
+
+/* --Methode-- */
+//++
+int  NTuple::FillFromASCIIFile(string const& fn, float defval)
+//
+//	Remplit le ntuple a partir d'un fichier ASCII.
+//	Renvoie le nombre de lignes ajoutees.
+//--
+{
+if (NbColumns() < 1)  { 
+  cout << "NTuple::FillFromASCIIFile() Ntuple has " << NbColumns() << " columns" << endl;
+  return(-1);
+  }
+FILE * fip = fopen(fn.c_str(), "r");
+if (fip == NULL) {
+  cout << "NTuple::FillFromASCIIFile() Error opening file " << fn << endl;
+  return(-2);
+  }
+
+char lineb[4096];
+char *line;
+char buff[64];
+char* ccp;
+int i,j,l,kk;
+int postab, posb;
+float* xv = new float[NbColumns()];
+
+int nlread = 0;
+int nvar = NbColumns();
+// On boucle sur toutes les lignes
+while (fgets(lineb,4096,fip) != NULL) {
+  lineb[4095] = '\0';
+  j = 0; line = lineb;
+//  On enleve les espaces et tab de debut 
+  while ( (line[j] != '\0') && ((line[j] == ' ') || (line[j] == '\t')) )  j++;
+  line = lineb+j; 
+// Il faut que le premier caractere non-espace soit un digit, ou + ou - ou .
+  if (!( isdigit(line[0]) || (line[0] == '+') || (line[0] == '-') || (line[0] == '.') ))  continue;
+  ccp = line;
+  for(kk=0; kk<nvar; kk++)  xv[kk] = defval;
+  for(kk=0; kk<nvar; kk++) {
+// Les mots sont separes par des espaces ou des tab
+    postab = posc(ccp, '\t' );
+    posb = posc(ccp, ' ' );
+    if (postab >= 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-- */
+uint_4 NTuple::NbLines() const
+{
+return(NEntry());
+}
+/* --Methode-- */
+uint_4 NTuple::NbColumns() const
+{
+return(NVar());
+}
+
+/* --Methode-- */
+r_8 * NTuple::GetLineD(int n) const
+{
+return(GetVecD(n));
+}
+
+/* --Methode-- */
+r_8 NTuple::GetCell(int n, int k) const
+{
+return(GetVal(n, k));
+}
+
+/* --Methode-- */
+r_8 NTuple::GetCell(int n, string const & nom) const
+{
+return(GetVal(n, nom.c_str()));
+}
+
+/* --Methode-- */
+//++
+void  NTuple::GetMinMax(int k, double& min, double& max)  const
 //
 //	Retourne le minimum et le maximum de la variable `k'.
@@ -241,5 +437,5 @@
 if ( (k < 0) || (k >= mNVar) )    return;
 int jb,ib,i;
-float x;
+double x;
 i=0;
 for(jb=0; jb< mNBlk; jb++)
@@ -256,37 +452,113 @@
 
 /* --Methode-- */
-//++
-DVList&  NTuple::Info()
-//
-//	Renvoie une référence sur l'objet DVList Associé
-//--
-{
-if (mInfo == NULL)  mInfo = new DVList;
-return(*mInfo);
-}
-
-/* --Methode-- */
-//++
-void  NTuple::Print(int num, int nmax)  const
-//
-//	Imprime `nmax' evenements a partir du numero `num'.
-//--
-{
-int i,j;
-
-printf("Num     ");
-for(i=0; i<mNVar; i++)  printf("%8s ", mNames+i*LENNAME1);
-putchar('\n');
-
-if (nmax <= 0)  nmax = 1;
-if (num < 0)  num = 0;
-nmax += num;
-if (nmax > mNEnt) nmax = mNEnt;
-for(i=num; i<nmax; i++) {
-  GetVec(i, NULL); 
-  printf("%6d  ", i);  
-  for(j=0; j<mNVar; j++)  printf("%8g ", (float)mVar[j]);
-  putchar('\n');
-}
+void NTuple::GetMinMax(string const & nom, double& min, double& max)   const
+{
+GetMinMax(IndexNom(nom.c_str()), min, max);
+}
+
+/* --Methode-- */
+int NTuple::ColumnIndex(string const & nom)  const
+{
+return(IndexNom(nom.c_str()));
+}
+
+/* --Methode-- */
+string NTuple::ColumnName(int 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<mNVar; i++) {
+  if ( (i%5 == 0) && (i > 0) )  rets += ";";  
+  if (i%5 == 0)   rets += "\ndouble "; 
+  else rets += ",";
+  rets += mNames+i*LENNAME1;
+  }
+rets += "; \n";
+if (nomx) { 
+  char buff[256];
+  for(i=0; i<mNVar; i++) {
+    sprintf(buff,"%s=%s[%d]; ",  mNames+i*LENNAME1, nomx, i);
+    rets += buff;
+    if ( (i%3 == 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<mNVar; i++) {
+  sprintf(buff, "%8s ", mNames+i*LENNAME1);
+  rets += buff;
+  }
+rets += '\n';
+return(rets);
+}
+
+/* --Methode-- */
+//++
+string NTuple::LineToString(int n) const
+//	Retourne une chaine de caracteres avec le contenu de la ligne "n"
+//	utilisable pour une impression
+//--
+{
+char buff[32];
+double* val;
+val = GetLineD(n);
+sprintf(buff,"%6d: ",n);  
+string rets=buff;
+int i;
+for(i=0; i<mNVar; i++) {
+  sprintf(buff, "%8.3g ", val[i]);
+  rets += buff;
+  }
+rets += '\n';
+return(rets);
+}
+
+
+/* --Methode-- */
+//++
+void   ObjFileIO<NTuple>::WriteSelf(POutPersist& s)  const
+//
+//	Ecriture ppersist du ntuple.
+//--
+{
+char strg[256];
+if (dobj->mInfo)  sprintf(strg, "NVar=%6d  NEnt=%9d  BlkSz=%6d NBlk=%6d  HasInfo", 
+                          (int)dobj->mNVar, (int)dobj->mNEnt, (int)dobj->mBlk, (int)dobj->mNBlk);
+else sprintf(strg, "NVar=%6d  NEnt=%9d  BlkSz=%6d NBlk=%6d ", 
+                   (int)dobj->mNVar, (int)dobj->mNEnt, (int)dobj->mBlk, (int)dobj->mNBlk);
+s.PutLine(strg);
+s.PutI4(dobj->mNVar);
+s.PutBytes(dobj->mNames, dobj->mNVar*LENNAME1);
+s.PutI4(dobj->mNEnt);
+s.PutI4(dobj->mBlk);
+s.PutI4(dobj->mNBlk);
+if (dobj->mInfo)  s << (*(dobj->mInfo));
+int jb;
+for(jb=0; jb<dobj->mNBlk; jb++)
+  s.PutR4s(dobj->mPtr[jb], dobj->mNVar*dobj->mBlk); 
 return;
 }
@@ -294,129 +566,46 @@
 /* --Methode-- */
 //++
-void  NTuple::Show(ostream& os)  const
-//
-//	Imprime l'information generale sur le ntuple.
-//--
-{
-os << "NTuple: NVar= " << mNVar << " NEnt=" << mNEnt  
-   << " (Blk Sz,Nb= " << mBlk << " ," << mNBlk << ")\n";
-os << "            Variables       Min      Max       \n";
-int i;
-float min, max;
-char buff[128];
-for(i=0; i<mNVar; i++) {
-  GetMinMax(i, min, max);
-  sprintf(buff, "%3d  %16s  %10g  %10g \n", i, mNames+i*LENNAME1, min, max);
-  os << (string)buff ;
-  }
-os << endl;
-}
-
-
-/* --Methode-- */
-//++
-void  NTuple::WriteSelf(POutPersist& s)  const
-//
-//	Ecriture ppersist du ntuple.
-//--
-{
+void  ObjFileIO<NTuple>::ReadSelf(PInPersist& s)
+//
+//	Lecture ppersist du ntuple.
+//--
+{
+
+dobj->Clean();
+
 char strg[256];
-if (mInfo)  sprintf(strg, "NVar=%6d  NEnt=%9d  BlkSz=%6d NBlk=%6d  HasInfo", 
-                          (int)mNVar, (int)mNEnt, (int)mBlk, (int)mNBlk);
-else sprintf(strg, "NVar=%6d  NEnt=%9d  BlkSz=%6d NBlk=%6d ", 
-                   (int)mNVar, (int)mNEnt, (int)mBlk, (int)mNBlk);
-s.PutLine(strg);
-s.PutI4(mNVar);
-s.PutBytes(mNames, mNVar*LENNAME1);
-s.PutI4(mNEnt);
-s.PutI4(mBlk);
-s.PutI4(mNBlk);
-if (mInfo)  s << (*mInfo);
-int jb;
-for(jb=0; jb<mNBlk; jb++)
-  s.PutR4s(mPtr[jb], mNVar*mBlk); 
-return;
-}
-
-/* --Methode-- */
-//++
-void  NTuple::ReadSelf(PInPersist& s)
-//
-//	Lecture ppersist du ntuple.
-//--
-{
-
-  Clean();
-  
-  char strg[256];
-  s.GetLine(strg, 255);
-  // Pour savoir s'il y avait un DVList Info associe
-  bool hadinfo = false;
-  if (strncmp(strg+strlen(strg)-7, "HasInfo", 7) == 0)  hadinfo = true;
-
-  s.GetI4(mNVar);
-  mNames = new char[mNVar*LENNAME1];
-  mVar = new r_4[mNVar];
-  mVarD = new r_8[mNVar];
-  s.GetBytes(mNames, mNVar*LENNAME1);
-  s.GetI4(mNEnt);
-  s.GetI4(mBlk);
-  s.GetI4(mNBlk);
-
-  if (hadinfo) {    // Lecture eventuelle du DVList Info
-    if (mInfo == NULL)  mInfo = new DVList;
-    s >> (*mInfo);
-  }
-
-  int jb; 
-  for(jb=0; jb<mNBlk; jb++) {
-    r_4* pt = new r_4[mNVar*mBlk];
-    mPtr.push_back(pt);
-    s.GetR4s(mPtr[jb], mNVar*mBlk); 
-  }
-}
-
-NTuple& NTuple::operator=(const NTuple &ntpl)
-{
-  mNVar= ntpl.mNVar;
-  mNEnt= ntpl.mNEnt;
-  mBlk = ntpl.mBlk;
-  mNBlk= ntpl.mNBlk;
-  
-  mVar= new r_4[mNVar];
-  for(int k = 0; k < mNVar; k++)
-    mVar[k]= ntpl.mVar[k];
-  
-  mVarD= new r_8[mNVar];
-  for(int k = 0; k < mNVar; k++)
-    mVarD[k]= ntpl.mVarD[k];
-  
-  mNames = new char[mNVar*LENNAME1];
-  for(int i = 0; i < mNVar; i++)
-    {
-      strncpy(mNames+i*LENNAME1,(ntpl.mNames)+i*LENNAME1, LENNAME);  
-      mNames[i*LENNAME1+LENNAME] = '\0'; 
-    }
-
-  for(int k = 0; k < mNBlk; k++)
-    {
-      r_4 *ptr= new r_4[mNVar*mBlk];
-      for(int i = 0; i < mNVar*mBlk; i++)
-	{
-	  *(ptr+i)= *(ntpl.mPtr[k]+i);
-	}
-      mPtr.push_back(ptr);
-    }
-
-  mInfo = new DVList;
-  if(ntpl.mInfo)  
-    {
-      *mInfo= *(ntpl.mInfo);
-    }
-  else
-    {
-      mInfo = NULL;
-    }
-
-  return *this;
-}
+s.GetLine(strg, 255);
+// Pour savoir s'il y avait un DVList Info associe
+bool hadinfo = false;
+if (strncmp(strg+strlen(strg)-7, "HasInfo", 7) == 0)  hadinfo = true;
+
+s.GetI4(dobj->mNVar);
+dobj->mNames = new char[dobj->mNVar*LENNAME1];
+dobj->mVar = new r_4[dobj->mNVar];
+dobj->mVarD = new r_8[dobj->mNVar];
+s.GetBytes(dobj->mNames, dobj->mNVar*LENNAME1);
+s.GetI4(dobj->mNEnt);
+s.GetI4(dobj->mBlk);
+s.GetI4(dobj->mNBlk);
+
+if (hadinfo) {    // Lecture eventuelle du DVList Info
+  if (dobj->mInfo == NULL)  dobj->mInfo = new DVList;
+  s >> (*(dobj->mInfo));
+  }
+
+int jb; 
+for(jb=0; jb<dobj->mNBlk; jb++) {
+  r_4* pt = new r_4[dobj->mNVar*dobj->mBlk];
+  dobj->mPtr.push_back(pt);
+  s.GetR4s(dobj->mPtr[jb], dobj->mNVar*dobj->mBlk); 
+}
+
+}
+
+#ifdef __CXX_PRAGMA_TEMPLATES__
+#pragma define_template ObjFileIO<NTuple>
+#endif
+
+#if defined(ANSI_TEMPLATES) || defined(GNU_TEMPLATES)
+template class ObjFileIO<NTuple>;
+#endif
