Index: /trunk/SophyaPI/PIext/pawexecut.cc
===================================================================
--- /trunk/SophyaPI/PIext/pawexecut.cc	(revision 2816)
+++ /trunk/SophyaPI/PIext/pawexecut.cc	(revision 2817)
@@ -123,5 +123,5 @@
 
 kw = "n/merge/col";
-usage = "Merge ntuples (by adding columns)";
+usage = "Merge ntuples (by adding columns for each line)";
 usage += "\n n/merge/col nt nt_1[,ext] nt_2[,ext] ... nt_n[,ext]";
 usage += "\n Merge ntuples nt_i columns into ntuple nt";
@@ -129,4 +129,24 @@
 usage += "\n   if \"ext\"=\"!\" no extension is added";
 usage += "\n   if no \"ext\" is given, automatic extension \"_0\" \"_1\" \"_2\" ...";
+piac->RegisterCommand(kw,usage,this,hgrp);
+
+kw = "n/assoc/col";
+usage = "Merge ntuples columns with an association index";
+usage += "\n n/assoc/col ntass[,u/i] nt_1[,ext] nt_2[,ext] nt_assoc[,icass]";
+usage += "\n Merge ntuples nt_1 and nt_2 columns into ntuple ntass";
+usage += "\n   with line association number given by ntuple nt_assoc";
+usage += "\n ---";
+usage += "\n icass: association number given by column \"icass\" of nt_assoc (def=0)";
+usage += "\n ---";
+usage += "\n ext : character string to add at the end of the ntuple variable names";
+usage += "\n   if \"ext\"=\"!\" no extension is added";
+usage += "\n   if no \"ext\" is given, automatic extension \"_0\" \"_1\" \"_2\" ...";
+usage += "\n ---";
+usage += "\n u   : do the union of all the lines of nt_1 and nt_2";
+usage += "\n       (all ssociated and un-associated lines of nt_1 and nt_2)";
+usage += "\n i   : do the intersection of all the lines of nt_1 and nt_2";
+usage += "\n       (only associated lines of nt_1 and nt_2)";
+usage += "\n def : write all lines of nt_1 with possible associated line of nt_2";
+usage += "\n       (number of entries of ntass = number of entries of nt_1)";
 piac->RegisterCommand(kw,usage,this,hgrp);
 
@@ -302,4 +322,6 @@
 } else if(kw == "n/merge/col") {
   n_merge_col(tokens); return(0);
+} else if(kw == "n/assoc/col") {
+  n_assoc_col(tokens); return(0);
 } else if(kw == "n/copy") {
   n_copy(tokens); return(0);
@@ -919,7 +941,7 @@
      nvar = nt1->NVar();
      vector<string> sntvn;
-     for(int i=0;i<nvar;i++) sntvn.push_back(nt1->ColumnName(i));
+     for(int iv=0;iv<nvar;iv++) sntvn.push_back(nt1->ColumnName(iv));
      char **ntvn = new char*[nvar];
-     for(int i=0;i<nvar;i++) ntvn[i] = const_cast<char *>(sntvn[i].c_str());
+     for(int iv=0;iv<nvar;iv++) ntvn[iv] = const_cast<char *>(sntvn[iv].c_str());
      nt = new NTuple(nvar,ntvn);
      delete [] ntvn;
@@ -930,5 +952,5 @@
    int n = (nvar1>nvar)? nvar1: nvar;
    r_8 *xnt1 = new r_8[n];
-   for(int i=0;i<n;i++) xnt1[i]=0.;
+   for(int iev=0;iev<n;iev++) xnt1[iev]=0.;
    for(uint_4 iev=0;iev<(uint_4)nt1->NEntry();iev++) {
      nt1->GetVecD(iev,xnt1);
@@ -1008,6 +1030,6 @@
    posfirst.push_back(ipos);
    if(nt1->NEntry()>(int_4)nentmax) nentmax = nt1->NEntry();
-   for(int i=0;i<nt1->NVar();i++) {
-     string str = nt1->ColumnName(i) + ext;
+   for(int iv=0;iv<nt1->NVar();iv++) {
+     string str = nt1->ColumnName(iv) + ext;
      varname.push_back(str);
    }
@@ -1026,5 +1048,5 @@
  int nvar = varname.size();
  char **ntvn = new char*[nvar];
- for(int i=0;i<nvar;i++) ntvn[i] = const_cast<char *>(varname[i].c_str());
+ for(int iv=0;iv<nvar;iv++) ntvn[iv] = const_cast<char *>(varname[iv].c_str());
  NTuple * nt = new NTuple(nvar,ntvn);
  //for(int i=0;i<(int_4)ntname.size();i++) cout<<ntname[i]<<" , p="<<posfirst[i]<<endl;
@@ -1048,4 +1070,160 @@
      <<" ntuples, "<<nt->NEntry()<<" entries"<<endl;
  if(nt->NEntry()>0) omg.AddObj(nt,nament); else delete nt;
+
+ return;
+}
+
+/* methode */
+void PAWExecutor::n_assoc_col(vector<string>& tokens)
+{
+ if(tokens.size()<4) {
+   cerr<<"Usage: n/assoc/col ntass[,u] nt_1[,ext] nt_2[,ext] nt_assoc[,icass]"<<endl;
+   return;
+ }
+
+ NamedObjMgr omg;
+
+ // decodage du nom du ntuple final associe
+ // do_merge = 0  :  on remplit toutes les lignes de nt_1 associees ou non
+ //                  lignes associees + non-associees de nt_1
+ //                  -> ntass.NEntry == nt_1.NEntry
+ //          = 1  :  on remplit uniquement les lignes associees
+ //                  lignes associees uniquement
+ //                  -> ntass.NEntry <= min(nt_1.NEntry,nt_2.NEntry)
+ //          = 2  :  on remplit l'union des lignes
+ //                  lignes associees + non-associees de nt_1 + non-associees de nt_2
+ //                  -> ntass.NEntry >= max(nt_1.NEntry,nt_2.NEntry)
+ uint_2 do_merge=0;
+ string ntmerge = tokens[0];
+ int lc = tokens[0].size();
+ int p = tokens[0].find(',');
+ if(p>=0 && p<lc) {
+   ntmerge = ntmerge.substr(0,p);
+   p = tokens[0].find(",u");
+   if(p>=0 && p<lc) do_merge = 2;
+   p = tokens[0].find(",i");
+   if(p>=0 && p<lc) do_merge = 1;
+ }
+ cout<<"n_assoc_col: final ntuple "<<ntmerge<<", do_merge="<<do_merge<<endl;
+
+ // boucle pour decoder et valider les 3 ntuples
+ NTuple *nt[3];
+ string ntname;
+ vector<string> varname;
+ int icass = 0;
+
+ for(int i=0;i<3;i++) {
+
+   // Decode NTuple name and extension
+   ntname = tokens[i+1];
+   int_4 lc = ntname.size();
+   string ext = "";
+   int p = ntname.find(',');
+   if(p>=0 && p<lc) {
+     if(p<lc-1) ext = ntname.substr(p+1,lc-p-1);
+     if(p>0) ntname = ntname.substr(0,p); else ntname = "";
+   }
+   // choose the extension: given,automatic,none
+   if(i==2) {  // numero de colonne avec l'index d'association
+     if(ext[0] == '!') ext = "";
+     if(ext.size()>0) icass = atoi(ext.c_str());
+   } else {
+     if(ext.size()<1) {
+       char str[8]; sprintf(str,"_%d",i);
+       ext = str;
+     } else if(ext[0] == '!') {
+       ext = "";
+     }
+   }
+
+   AnyDataObj* mobj = omg.GetObj(ntname);
+   if(mobj==NULL) {
+     cout<<"n_assoc_col Error: unknow object "<<ntname<<" ("<<tokens[i]<<")"<<endl;
+     return;
+   }
+   nt[i] = dynamic_cast<NTuple*>(mobj);
+   if(nt[i]==NULL) {
+     cout<<"n_assoc_col Error: "<<ntname<<" not a NTuple"<<endl;
+     return;
+   }
+   if(nt[i]->NEntry()==0) {
+     cout<<"n_assoc_col Error: "<<ntname<<" is empty"<<endl;
+     return;
+   }
+   if(nt[i]->NVar()==0) {
+     cout<<"n_assoc_col Error: "<<ntname<<" has no variable"<<endl;
+     return;
+   }
+
+   if(i<2)
+     for(int iv=0;iv<nt[i]->NVar();iv++) {
+       string str = nt[i]->ColumnName(iv) + ext;
+       varname.push_back(str);
+     }
+
+ }
+
+ // Checking size of associated ntuple
+ if(nt[0]->NEntry() != nt[2]->NEntry()) {
+   cout<<"n_assoc_col Error: nentries mismatch "
+       <<" first ntuple"<<"="<<nt[0]->NEntry()
+       <<", assoc ntuple"<<"="<<nt[2]->NEntry()<<endl;
+   return;
+ }
+ if(icass<0 || icass>=nt[2]->NVar()) {
+   cout<<"n_assoc_col Error: bad association column number "
+       <<icass<<" / "<<nt[2]->NVar()<<endl;
+   return;
+ }
+
+ // create receiving ntuple
+ int nvar = varname.size();
+ char **ntvn = new char*[nvar];
+ for(int iv=0;iv<nvar;iv++) ntvn[iv] = const_cast<char *>(varname[iv].c_str());
+ NTuple * ntass = new NTuple(nvar,ntvn);
+ delete [] ntvn;
+
+ // Filling with current ntuple
+ // the first column gives the associated line in nt[1]
+ int_4 nfill[2]={0,0};
+ r_8 *xass = new r_8[nt[2]->NVar()];
+ r_8 *xnt = new r_8[nvar];
+ uint_2 *use2 = NULL;
+ if(do_merge==2) {
+   use2 = new uint_2[nt[1]->NEntry()];
+   for(int i=0;i<nt[1]->NEntry();i++) use2[i] = 0;
+ }
+ for(int iev=0;iev<nt[0]->NEntry();iev++) {
+   nt[2]->GetVecD(iev,xass);
+   int iass = (xass[icass]<0.) ? -1: int(xass[icass]+0.5);
+   bool okass = (iass>=0 && iass<nt[1]->NEntry());
+   if(do_merge==1 && !okass) continue; // pas d'assoc et intersection demandee
+   for(int iv=0;iv<nvar;iv++) xnt[iv]=0.;
+   nt[0]->GetVecD(iev,xnt);
+   if(okass) {
+     nt[1]->GetVecD(iass,&xnt[nt[0]->NVar()]);
+     if(do_merge==2) use2[iass] = 1;
+   } else nfill[0]++;
+   ntass->Fill(xnt);
+ }
+ // Filling with remaining unassociated in nt[1] if requested
+ if(do_merge==2) {
+   for(int iev=0;iev<nt[1]->NEntry();iev++) {
+     if(use2[iev]!=0) continue; // deja rempli
+     for(int iv=0;iv<nvar;iv++) xnt[iv]=0.;
+     nt[1]->GetVecD(iev,&xnt[nt[0]->NVar()]);
+     ntass->Fill(xnt);
+     nfill[1]++;
+   }
+ }
+
+ // Ending and saving merged ntuple
+ delete [] xnt; delete [] xass;
+ if(use2) delete [] use2;
+ cout<<"n_assoc_col: ntuple "<<ntmerge
+     <<" filled with "<<ntass->NEntry()<<" entries"
+     <<", unassoc in nt_1="<<nfill[0]
+     <<", unassoc in nt_2="<<nfill[1]<<endl;
+ omg.AddObj(ntass,ntmerge);
 
  return;
Index: /trunk/SophyaPI/PIext/pawexecut.h
===================================================================
--- /trunk/SophyaPI/PIext/pawexecut.h	(revision 2816)
+++ /trunk/SophyaPI/PIext/pawexecut.h	(revision 2817)
@@ -29,4 +29,5 @@
   void  n_merge(vector<string>& tokens);
   void  n_merge_col(vector<string>& tokens);
+  void  n_assoc_col(vector<string>& tokens);
   void  n_copy(vector<string>& tokens);
   void  h_integ(vector<string>& tokens);
