Problem with multiple use of contour line as TCutG

Dear ROOT guys,

in a 2D distribution, I am trying to find the contour level that will cut away, say, 10% of the data. To achieve this, I start from the FirstContour.C tutorial example that shows how to retrieve the first contour of a histogram contour plot. Now I simply want to repeat this procedure by raising the level of the first contour step by step. But as soon as I repeat the procedure to retrieve the contour and use it to generate a cut in a loop, ROOT produces a segmentation violation (somewhere in TSelectorDraw::ClearFormula it seems).

How would I have to adapt my code so that I can safely run the procedure in a loop?

Many thanks in advance!

Here’s my macro, based on $ROOTSYS/tutorials/hist/FirstContour.C
Note: to run it, you should be in the same directory, or have hsimple.C in the …/ directory!

void FirstContour()
{
   //this macro generates a color contour plot by selecting entries
   //from an ntuple file.
   //The TGraph object corresponding to the first contour line is 
   //accessed and displayed into a separate canvas.
   //Author: Rene Brun
   
   TString dir = gSystem->UnixPathName(TCint::GetCurrentMacroName());
   dir.ReplaceAll("FirstContour.C","../hsimple.C");
   dir.ReplaceAll("/./","/");
   if (!gInterpreter->IsLoaded(dir.Data())) gInterpreter->LoadMacro(dir.Data());
   TFile *file = (TFile*)gROOT->ProcessLineFast("hsimple(1)");
   if (!file) return;
   TTree *ntuple = (TTree*)file->Get("ntuple");
   
   TCanvas *c1 = new TCanvas("c1","Contours",10,10,800,600);
   gStyle->SetPalette(1);
   TH2D* histo = new TH2D("histo","histo", 50, -5, 5, 50, -5, 5);

   Double_t n0 = ntuple->GetEntries();

   ntuple->Draw("py:px>>histo","px*px+py*py < 20");

   Double_t conts[3];
   conts[0] = 20; 
   conts[1] = 60;
   conts[2] = 100;
    
   //   for (Int_t i=10;i<20;i+=10) { // run it once: no problem
   for (Int_t i=10;i<100;i+=10) {  // run it several times: crash!

     conts[0] = i;

     histo->SetContour(3,conts);
     histo->Draw("contz,list");

     //we must call Update to force the canvas to be painted.  When 
     //painting the contour plot, the list of contours is generated
     //and a reference to it added to the Root list of special objects
     c1->Update();
      
     TObjArray *contours = 
       (TObjArray*)gROOT->GetListOfSpecials()->FindObject("contours");
     TList *lcontour1 = (TList*)contours->At(0);
     TGraph *gc1 = (TGraph*)lcontour1->First();
     gc1->SetMarkerStyle(21);
     gc1->Draw("alp");
   
     //We make a TCutG object with the array obtained from this graph
     TCutG *cutg = new TCutG("cutg",gc1->GetN(),gc1->GetX(),gc1->GetY());
     cutg->SetVarX("px");
     cutg->SetVarY("py");
     
     TH2D *histo2 = new TH2D("histo2","histo2", 50, -5, 5, 50, -5, 5);
     ntuple->Draw("py:px>>histo2",cutg->GetName());
     Double_t ncut = histo2->GetEntries();

     if (cutg) delete cutg;
     if (histo2) delete histo2;

     Double_t frac = ncut/n0;
     cout << " i = " << i << " n(cut) = " << ncut << " fraction = " << frac << endl;


   }
}          

It seems like the problem lies in the ntuple. Apparently, it does not like to have another TCutG applied to it (why I don’t know). I found a work-around in which I clone the ntuple everytime before I apply the graphical cut to fill the histogram. The cloning can be pretty heavy for large ntuples, so I am wondering if there is no other way to do it? I would need something like a Reset() method that does not reset the data itself, just the other stuff the ntuple carries with it.

Something is still fishy with my workaround: it yields the numbers as desired and does not crash, but as soon as I terminate my ROOT session, it will crash upon exiting. I am using 5.18.00, but do not expect any difference with respect to 5.20.

Does anyone have a better understanding, or a better solution for this?

Thanks again,

Thomas

I am posting the same macro, now with the workaround:

void FirstContour()
{
   //this macro generates a color contour plot by selecting entries
   //from an ntuple file.
   //The TGraph object corresponding to the first contour line is 
   //accessed and displayed into a separate canvas.
   //Author: Rene Brun
   
   TString dir = gSystem->UnixPathName(TCint::GetCurrentMacroName());
   dir.ReplaceAll("FirstContour.C","../hsimple.C");
   dir.ReplaceAll("/./","/");
   if (!gInterpreter->IsLoaded(dir.Data())) gInterpreter->LoadMacro(dir.Data());
   TFile *file = (TFile*)gROOT->ProcessLineFast("hsimple(1)");
   if (!file) return;
   TTree *ntuple = (TTree*)file->Get("ntuple");
   
   TCanvas *c1 = new TCanvas("c1","Contours",10,10,800,600);
   gStyle->SetPalette(1);
   TH2D* histo = new TH2D("histo","histo", 50, -5, 5, 50, -5, 5);

   Double_t n0 = ntuple->GetEntries();

   ntuple->Draw("py:px>>histo","px*px+py*py < 20");

   Double_t conts[3];
   conts[0] = 20; 
   conts[1] = 60;
   conts[2] = 100;
    
   TTree* nt2 = 0;

   //   for (Int_t i=10;i<20;i+=10) {
   for (Int_t i=10;i<100;i+=10) {

     conts[0] = i;

     histo->SetContour(3,conts);
     histo->Draw("contz,list");

     //we must call Update to force the canvas to be painted.  When 
     //painting the contour plot, the list of contours is generated
     //and a reference to it added to the Root list of special objects
     c1->Update();
      
     TObjArray *contours = 
       (TObjArray*)gROOT->GetListOfSpecials()->FindObject("contours");
     TList *lcontour1 = (TList*)contours->At(0);
     TGraph *gc1 = (TGraph*)lcontour1->First();
     gc1->SetMarkerStyle(21);
     gc1->Draw("alp");
   
     //We make a TCutG object with the array obtained from this graph
     TCutG *cutg = new TCutG("cutg",gc1->GetN(),gc1->GetX(),gc1->GetY());
     cutg->SetVarX("px");
     cutg->SetVarY("py");
     
     TH2D *histo2 = new TH2D("histo2","histo2", 50, -5, 5, 50, -5, 5);
     nt2 = (TTree*)ntuple->Clone();

     nt2->Draw("py:px>>histo2",cutg->GetName());
     Double_t ncut = histo2->GetEntries();

     nt2->Reset();

     if (cutg) {delete cutg;cutg=0;}
     if (histo2) {delete histo2;histo2=0;}

     Double_t frac = ncut/n0;
     cout << " i = " << i << " n(cut) = " << ncut << " fraction = " << frac << endl;

   }

}          

Hi,

I can reproduce the problem and I am working on a solution.

Another work around is to end you loop withdelete ntuple; file->GetObject("ntuple",ntuple);This effectively does the reset you need.

Cheers,
Philippe.

Thanks for the reply.

The second workaround does not work for me. Have you actually tried it? Maybe I am doing something wrong (code attached).

I would be VERY interested in the second workaround, as my first workaround fills up my memory very quickly (cloning again and again the same ntuple…). Of course I want to delete these clones, but I just can’t (seg. viol.).

It seems like I cannot delete any ntuple that was previously used with a TCutG, at least not in this situation. Somewhere in ClearFormula it produces a segmentation violation.

Thomas

Below the code with (not-)workaround #2:

void FirstContour()
{
   //this macro generates a color contour plot by selecting entries
   //from an ntuple file.
   //The TGraph object corresponding to the first contour line is
   //accessed and displayed into a separate canvas.
   //Author: Rene Brun
   
   TString dir = gSystem->UnixPathName(TCint::GetCurrentMacroName());
   dir.ReplaceAll("FirstContour.C","../hsimple.C");
   dir.ReplaceAll("/./","/");
   if (!gInterpreter->IsLoaded(dir.Data())) gInterpreter->LoadMacro(dir.Data());
   TFile *file = (TFile*)gROOT->ProcessLineFast("hsimple(1)");
   if (!file) return;
   TTree *ntuple = (TTree*)file->Get("ntuple");
   
   TCanvas *c1 = new TCanvas("c1","Contours",10,10,800,600);
   gStyle->SetPalette(1);
   TH2D* histo = new TH2D("histo","histo", 50, -5, 5, 50, -5, 5);

   Double_t n0 = ntuple->GetEntries();

   ntuple->Draw("py:px>>histo","px*px+py*py < 20");

   Double_t conts[3];
   conts[0] = 20;
   conts[1] = 60;
   conts[2] = 100;
   
   //   for (Int_t i=10;i<20;i+=10) {
   for (Int_t i=10;i<100;i+=10) {

     conts[0] = i;

     histo->SetContour(3,conts);
     histo->Draw("contz,list");

     //we must call Update to force the canvas to be painted.  When
     //painting the contour plot, the list of contours is generated
     //and a reference to it added to the Root list of special objects
     c1->Update();
     
     TObjArray *contours =
       (TObjArray*)gROOT->GetListOfSpecials()->FindObject("contours");
     TList *lcontour1 = (TList*)contours->At(0);
     TGraph *gc1 = (TGraph*)lcontour1->First();
     gc1->SetMarkerStyle(21);
     gc1->Draw("alp");
   
     //We make a TCutG object with the array obtained from this graph
     TCutG *cutg = new TCutG("cutg",gc1->GetN(),gc1->GetX(),gc1->GetY());
     cutg->SetVarX("px");
     cutg->SetVarY("py");
     
     TH2D *histo2 = new TH2D("histo2","histo2", 50, -5, 5, 50, -5, 5);

     delete ntuple;  file->GetObject("ntuple",ntuple);
     ntuple->Draw("py:px>>histo2",cutg->GetName());
     Double_t ncut = histo2->GetEntries();

     if (cutg) {delete cutg;cutg=0;}
     if (histo2) {delete histo2;histo2=0;}

     Double_t frac = ncut/n0;
     cout << " i = " << i << " n(cut) = " << ncut << " fraction = " << frac << endl;

   }

}          

You need delete ntuple; file->GetObject("ntuple",ntuple); if (cutg) delete cutg; if (histo2) delete histo2; Cheers,
Philippe

Ah, yes. Great, that does it for me! Thank you so much!! :smiley:

Whereas I am completely happy for today (and the following two), it does look like there is a problem somewhere in the handling of ntuples with TCutGs…

Thanks again,

Thomas

[quote]Whereas I am completely happy for today (and the following two), it does look like there is a problem somewhere in the handling of ntuples with TCutGs… [/quote]Yes, I know :slight_smile: I am working on it.

Cheers,
Philippe

Hi,

The underlying problem with TCutG have been solved in the SVN repository.

Cheers,
Philippe.