A problem writing histograms to a file

Greetings! This is my first post, apologies in advance for any mistakes.

I’m trying to write a macro that copies a root file, and then I loop over the copy, find all of it’s histograms, and normalize them. After the macro execution, I expect the output file to have the normalized histograms, but they appear as they were. I don’t understand why I’m not doing it properly.

I’ve also tried normalizing the histograms in the original file and then making a copy, to keep both, but it hasn’t worked, I appreciate any help.

The code (Part of it, I know the method form normalizing works, but if that can be the problem, please let me know) :


void histo_norm(){

  vector<string> input_vector;
  string input_file;
  vector<string> output_vector;
  std::cout << "Name the files to read (When you're finished, enter *):" << std::endl;

  while(input_file != "*"){
    std::cin >> input_file;
    input_vector.push_back(input_file);

    if (input_file == "*") break;

  }


  for(int n = 0 ; input_vector.size() > n ; n++){

    stringstream file_stream;
    file_stream << "output_" << input_vector[n];
    output_vector.push_back(file_stream.str());

    //  gSystem->CopyFile(input_vector[n].c_str(), output_vector[n].c_str());

    TFile *input_file = TFile::Open(input_vector[n].c_str());
    //f->ls();
    TDirectory *input_dir = gDirectory;

    TIter next_dir(input_dir->GetListOfKeys());
    TKey *dir_key;

    while((dir_key = (TKey*) next_dir())){
      if(dir_key->IsFolder()){                                     
        input_dir->cd(dir_key->GetName());                           
        input_file->cd();
        TIter next_folder(gDirectory->GetListOfKeys());             
        TKey *key_folder;
        while((key_folder = (TKey*) next_folder())){ 
          TClass *cl = gROOT->GetClass(key_folder->GetClassName());  
          if(!cl->InheritsFrom("TH1")) continue;                     
          TH1 *h = (TH1*)key_folder->ReadObj();                        
          Normalize(h , 1.0);
          TFile output(output_vector[n].c_str(),"NEW");
          output.Write();   //I want the histograms to be written in the output file, but it appears empty.



        }
      }
    }
  }
}



Thank you and best regards!


ROOT Version: 6.14.06
Platform: Ubuntu 18.04
Compiler: g++ 7.4.0


Hi,
after opening the TFile you should do

h->Write();

Then close the output file .

Cheers
Stefano

1 Like

Thank you for your answer!

I’ve tried this, it outputs nothing, sadly.

Do you happen to know another way of doing this? I’ve tried lots of things and nothing seems to work.

Have you tried moving the “TFile output…” line just before doing “TH1 *h…”? Also, have you checked that h is actually created and normalised with this exact code (i.e. can you draw it, even if it’s not saved)? And don’t forget to properly close the file/s after writing.

1 Like

Thank you for your answer!

I’ve tried this, and it doesn’t output anything.

I’ve checked the normalization, it works fine when you write it to an output file in the “ps” format. I doesn’t work for printing to an output “.root” file. I can even draw them to a TCanvas, but a root file is the problem.

Try:

void histo_norm(){

  vector<string> input_vector;
  string input_file;
  std::cout << "Name the files to read (When you're finished, enter *):" << std::endl;

  while(input_file != "*"){
    std::cin >> input_file;
    input_vector.push_back(input_file);

    if (input_file == "*") break;

  }


  for(int n = 0 ; input_vector.size() > n ; n++){
    TFile *output = TFile::Open(TString::Format("output_%s", (input_vector[n]).c_str()), "RECREATE");

    TFile *input_file = TFile::Open(input_vector[n].c_str());
    //f->ls();
    TDirectory *input_dir = gDirectory;

    TIter next_dir(input_dir->GetListOfKeys());
    TKey *dir_key;

    while((dir_key = (TKey*) next_dir())){
      if(dir_key->IsFolder()){                                     
        input_dir->cd(dir_key->GetName());                           
        input_file->cd();
        TIter next_folder(gDirectory->GetListOfKeys());             
        TKey *key_folder;
        while((key_folder = (TKey*) next_folder())){ 
          TClass *cl = gROOT->GetClass(key_folder->GetClassName());  
          if(!cl->InheritsFrom("TH1")) continue;                     
          TH1 *h = (TH1*)key_folder->ReadObj();
	  if (h) {
	    h->SetDirectory(output);
	    Normalize(h , 1.0);
	  }
        }
      }
    }

    delete input_file;

    output->Write();
    delete output;
  }
}
1 Like

Thanks for the reply!

I ran it, and it outputs a root file, but it’s empty.
Maybe save them to a TList and write them to a file afterward? I tried something like that but when I iterate over the TList nothing happens.

See if you do not overwrite histograms or files:

    // ...
    TFile *output = TFile::Open(TString::Format("output_%s", (input_vector[n]).c_str()), "RECREATE");
    std::cout << "Opening " << output->GetName() << std::endl;
    // ...
            h->SetDirectory(output);
	    std::cout << "Connecting " << h->GetName() << std::endl;
            // ...
    std::cout << "Closing " << output->GetName() << std::endl;
    delete output;
    // ...

I ran that, this is my output:

root [0] .x histo_norm_2.cc 
Name the files to read (When you're finished, enter *):
zz_nocut-1.root
*
Opening output_zz_nocut-1.root
Closing output_zz_nocut-1.root
Opening output_*
Error in <TFile::TFile>: file * does not exist
Closing output_*

It seems no histograms are being written…

Actually what you see is that NO histogram has been retrieved from your “input_file” and, in the end, you even try to use a file called “*”.

This is a mistake in the previous if, for some reason , when I input “" to make the code stop the instance that reads the name of the file, it searches for a file called "” that does not exist. I’ll try to fix this.

Why does it not retrieve the histograms from my input file? There’s some directories and the histograms are inside, but the loop that reads the file loops over the folders, opening them and then getting the histograms to normalize them.

Update: I managed to make the macro read all of the histograms, but none are written in the output file, still.

Show the “Opening + Connecting + Closing” output.

Sure, here it is:

root [0] .x histo_norm_2.cc 
Name the files to read (When you're finished, enter *):
zz_nocut-1.root
*
Opening output_zz_nocut-1.root
Connecting Nevents
Connecting nJets
Connecting nTaus
// ... histogram names
tau2PtNon-normalizable


It does not give a closing output.

No “Closing”, no fun.

Damn.

But I only changed this:

 if(dir_key->IsFolder()){
        input_file->cd();
        input_dir->cd(dir_key->GetName());
        //input_file->cd();  This changed place, that was it. It's a line early in the code,
        TIter next_folder(gDirectory->GetListOfKeys());
        TKey *key_folder;

 

Nothing I try seems to work to write the histograms to the output file. My supervisor told me that it’s because I’m not writing them to folders and they may be overwritten when I write them, I’ll see if making a file structure solves the problem, I’ll update this post if I find a solution.

Post your current source code again.

I’ve not finished the file system part, but the code is pretty much the same:


void histo_norm_2(){

  vector<string> input_vector;
  string input_file;
  std::cout << "Name the files to read (When you're finished, enter *):" << std::endl;

  while(input_file != "*"){
    std::cin >> input_file;
    input_vector.push_back(input_file);

    if (input_file == "*") break;

  }


  for(int n = 0 ; input_vector.size() > n ; n++){
    TFile *input_file = TFile::Open(input_vector[n].c_str());
    //f->ls();
    TDirectory *input_dir = gDirectory;

    TIter next_dir(input_dir->GetListOfKeys());
    TKey *dir_key;

    while((dir_key = (TKey*) next_dir())){
      if(dir_key->IsFolder()){                                     
        input_file->cd();
        input_dir->cd(dir_key->GetName());                           
        //input_file->cd();
        TIter next_folder(gDirectory->GetListOfKeys());             
        TKey *key_folder;

        while((key_folder = (TKey*) next_folder())){ 
          TClass *cl = gROOT->GetClass(key_folder->GetClassName());  
          if(!cl->InheritsFrom("TH1")) continue;                     
          TH1 *h = (TH1*)key_folder->ReadObj();
	  if (h) {
	    //h->SetDirectory(output);
	    std::cout << "Connecting " << h->GetName() << std::endl;
	    Normalize(h , 1.0);
	  }
        }
      }
    }

    delete input_file;
    TFile *output = TFile::Open(TString::Format("output_%s", (input_vector[n]).c_str()), "RECREATE");
    std::cout << "Opening " << output->GetName() << std::endl; 
    output->Write();
    std::cout << "Closing " << output->GetName() << std::endl;
    delete output;
  }
}


Please follow the way of dealing with the “output” EXACTLY like I show in my previous posts.

Same output as before, it opens the file, but it doesn’t close it.

root [0] .x histo_norm_2.cc 
Name the files to read (When you're finished, enter *):
ww_nocut-1.root
*
Opening output_ww_nocut-1.root
Connecting Nevents
Connecting nJets
Connecting nTaus
Connecting jetLeadPt
Connecting jetLeadEta
Connecting jetLeadPhi
Connecting jetSleadPt
....

//does not close it.