Post your fixed source code.
Also, say I want to include the file names in a config file (“in” format), and read them to the program, how would you do that? I’m confused as to how you do that.
Say I create the file with the names of my files, and then I read it like so:
TEnv *input_file = new TEnv("config_file");
input_file->ReadFile("names.in", kEnvChange);
How do I loop over the file names?
Sure it’s really 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 *output = TFile::Open(TString::Format("output_%s", (input_vector[n]).c_str()), "RECREATE");
std::cout << "Opening " << output->GetName() << std::endl;
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;
output->Write();
std::cout << "Closing " << output->GetName() << std::endl;
delete output;
}
}
Make sure that you uncomment the “SetDirectory” line.
The “Closing” must appear for every “n”.
Try to comment out the “Normalize” line.
I commented the normalizing line, It actually closed.
Still empty though.
About what you way, I don’t know if that line is the problem, as there is only histograms on those
folders. It’s not writing them to the file (still)… I could make another case, keeping the file structure.
As for this question : A problem writing histograms to a file , should I make another topic?
So, it seems that your “Normalize” is the problem.
Make sure that you uncomment the “SetDirectory” line, otherwise the “output” file will be empty.
This is my Normalize:
void Normalize (TH1 *h1, double scale){
Double_t ScaleFactor = 1.0;
if(h1->Integral() != 0) {
ScaleFactor = scale/(h1->Integral());
}
else{
std::cout << h1->GetName() << "Non-normalizable" << std::endl;
exit(1);
}
h1->Scale(ScaleFactor);
}
Also, I commented those lines and this is my output:
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
//Histogram names
Closing output_ww_nocut-1.root
Opening output_* //these are errors
Error in <TFile::TFile>: file * does not exist
Closing output_*
Still, the output file is empty. This is just routine by now.
If you still have problems, attach your “ww_nocut-1.root” file here for inspection.
#include "TH1.h"
#include "TFile.h"
#include "TDirectory.h"
#include "TCollection.h"
#include "TKey.h"
#include "TClass.h"
#include "TROOT.h"
#include <iostream>
#include <string>
#include <vector>
void Normalize(TH1 *h, Double_t norm) {
if ((!h) || (norm == 0.)) return; // just a precaution
Double_t integral = h->Integral();
if (integral != 0.) h->Scale(norm / integral);
else std::cout << h->GetName() << " is non-normalizable." << std::endl;
}
void histo_norm() {
std::vector<std::string> input_vector;
std::string input_string;
std::cout << "Name the files to read (When you're finished, enter *):" << std::endl;
while(std::cin >> input_string) {
if (input_string == "*") break;
input_vector.push_back(input_string);
}
for(unsigned int n = 0; n < input_vector.size(); n++) {
TFile *output = TFile::Open(TString::Format("output_%s", (input_vector[n]).c_str()), "RECREATE");
std::cout << "Opening " << output->GetName() << std::endl;
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()){ // Warning: TTree and TNtuple are also "folders"
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;
output->Write();
std::cout << "Closing " << output->GetName() << std::endl;
delete output;
}
}
Thank you very much! It works now. Now I only need to keep the folder structure of the file, but I can do that.
Have a nice day!
FYI, here is how you’d do it in Go (with groot):
package main
import (
"flag"
"log"
"github.com/pkg/errors"
"go-hep.org/x/hep/groot"
"go-hep.org/x/hep/groot/rhist"
"go-hep.org/x/hep/groot/riofs"
"go-hep.org/x/hep/groot/root"
"go-hep.org/x/hep/hbook/rootcnv"
)
func main() {
flag.Parse()
if flag.NArg() == 0 {
flag.Usage()
log.Fatalf("missing path(s) to file(s) to process")
}
for _, fname := range flag.Args() {
err := process(fname)
if err != nil {
log.Fatal(err)
}
}
}
func process(fname string) error {
f, err := groot.Open(fname)
if err != nil {
return errors.Wrapf(err, "could not open ROOT file")
}
defer f.Close()
fnew, err := groot.Create(fname + ".new")
if err != nil {
return errors.Wrapf(err, "could not create ROOT file")
}
defer fnew.Close()
err = riofs.Walk(f, func(path string, obj root.Object, err error) error {
name := path[len(f.Name()):]
switch obj := obj.(type) {
case *riofs.File:
// no op
return err
case riofs.Directory:
_, err = riofs.Dir(fnew).Mkdir(name)
if err != nil {
return errors.Wrapf(err, "could not create directory %q", path)
}
return err
case rhist.H1:
h, err := rootcnv.H1D(obj)
if err != nil {
return errors.Wrapf(err, "could not convert TH1 %q to hbook.H1", obj.Name())
}
h.Scale(1 / h.Integral())
// put normalized histo to the new ROOT file.
err = riofs.Dir(fnew).Put(name, rootcnv.FromH1D(h))
if err != nil {
return errors.Wrapf(err, "could not store normalized TH1 %q to %q", obj.Name(), path)
}
return err
default:
err = riofs.Dir(fnew).Put(name, obj)
if err != nil {
return errors.Wrapf(err, "could not store object (type=%T) to %q", obj, path)
}
}
return err
})
if err != nil {
return errors.Wrapf(err, "could not traverse ROOT file")
}
err = fnew.Close()
if err != nil {
return errors.Wrapf(err, "could not save ROOT file")
}
return nil
}
and here is an example:
$> root-ls ./histos.root
=== [./histos.root] ===
version: 61400
TDirectoryFile dir1 dir1 (cycle=1)
TDirectoryFile dir11 dir11 (cycle=1)
TH1D h1 h1 (cycle=1)
TDirectoryFile dir2 dir2 (cycle=1)
TDirectoryFile dir3 dir3 (cycle=1)
$> go run ./main.go ./histos.root
$> root-ls ./histos.new
root-ls ./histos.root.new
=== [./histos.root.new] ===
version: 61600
TDirectoryFile dir1 dir1 (cycle=1)
TDirectoryFile dir11 dir11 (cycle=1)
TH1D h1 h1 (cycle=1)
TDirectoryFile dir2 dir2 (cycle=1)
TDirectoryFile dir3 dir3 (cycle=1)
This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.