Writing Multiple histograms in output file

Hi all,
Following is a part of the code i am running,

   ............
   ............
   tree->SetBranchAddress("time", &time);
   tree->SetBranchAddress("idEvent",&idEvent);
   tree->SetBranchAddress("energy",&energy);
   TH1F *peakno = new TH1F("peakno","peakno",20000,0,20000);
   TH1F *intno = new TH1F("intno","intno",100,0,100);
   int N = tree->GetEntries();
   std::cout << "N= " << N  <<  std::endl;
   for (int i=0; i<N; i++) {
      tree->GetEntry(i);
      ULong_t nsig = time->size();
      double *sig = time->data();
      double *esig = energy->data();
      if (idEvent==0 ){
         for (ULong_t j=0; j<nsig; j++) {
            peakno->Fill(sig[j]);
         }
      }
   }
   TSpectrum *s = new TSpectrum(npeaks);
   Int_t nfound = s->Search(peakno,0.0,"",0.1);
   std::cout << "no of peaks = " << nfound << std::endl;
   intno->Fill(nfound);
   TFile *outputFile = new TFile(outFilename.c_str(),"RECREATE");
   std::cout << "Output file written to " << outFilename << std::endl;
   peakno->Write();
   intno->Write();

Here i can fill the histogram peakno and intno for idEvent==0 or 1 or 2 like that individually. idEvent runs from 0 to 8 . I need to produce the histogram for all of them . How do I can do that ? Could anyone help ?

Thank you

Make arrays of histograms for peakno and intno and fill them.

Some thing like that:

   ............

   tree->SetBranchAddress("time", &time);
   tree->SetBranchAddress("idEvent",&idEvent);
   tree->SetBranchAddress("energy",&energy);
   int i;
   
   const int n = 9;
   TH1F* peakno[n];
   TH1F* intno[n];
   for (i=0; i<n; i++) {
      peakno[i] = new TH1F(Form("peakno%d",i),Form("peakno%d",i),20000,0,20000);
      intno [i] = new TH1F(Form("intno%d",i),Form("intno%d",i),100,0,100);
   }
   
   int N = tree->GetEntries();
   std::cout << "N= " << N  <<  std::endl;
   for (i=0; i<N; i++) {
      tree->GetEntry(i);
      ULong_t nsig = time->size();
      double *sig = time->data();
      double *esig = energy->data();
      if (idEvent>=0 && idEvent<=8 ) {
         for (ULong_t j=0; j<nsig; j++) {
            peakno[idEvent]->Fill(sig[j]);
         }
      }
   }
   
   ............


Hello,

The modern way to treat your problem is through RDataFrame. It will also be valid once ROOT moves to its new columnar storage, RNTuple.
I provide below an example to accomplish what I think I understood you want to do: please correct me if I am wrong!
Please note the compactness and expressiveness of RDataFrame: this means less mistakes, less maintenance, less headaches…

To run the example root test.C.
You have 4 functions in the code:

  • test(): nothing, it just invokes the other 3 :slight_smile:
  • write(): I tried to emulate your root file, I hope it’s not too far from what you have
  • read_v1(): easy, string based but slightly underperformant version of RDataFrame
  • read_v2(): fully compiled, highly performant version of what you are trying to accomplish.

I took the freedom to plot all the quantities as well.

Let us know if you have further questions!

Cheers,
Danilo

void write(){
    // create a dummy dataset for this example
    // The types of the columns and the values are clearly made up!
    auto getValues = [](int nParticles) {
       std::vector<float> energy(nParticles);
       std::generate_n(energy.begin(), nParticles, [&](){return gRandom->Uniform(0., 100.);});
       return energy;
    };
    auto df = ROOT::RDataFrame(1024);
    df.Define("idEvent", []() { return int(gRandom->Uniform(0.5, 8.5)); })
      .Define("nParticles", []() { return int(gRandom->Uniform(0.5, 256.5)); })
      .Define("energy", getValues, {"nParticles"})
      .Define("time", getValues, {"nParticles"})
      .Snapshot("myTree", "myFile.root");
}

void read_v1(){
    // Extended version, using strings
    auto df = ROOT::RDataFrame("myTree","myFile.root");
    auto df0 = df.Filter("idEvent == 0");
    auto h_time_0 = df0.Histo1D("time");
    auto h_energy_0 = df0.Histo1D("energy");
    auto df1 = df.Filter("idEvent == 1");
    auto h_time_1 = df1.Histo1D("time");
    auto h_energy_1 = df1.Histo1D("energy");
     // ... and so on.

    for (auto &&h : {&h_time_0, &h_time_1, &h_energy_0, &h_energy_1}) {
       new TCanvas(); // this stays after the function returns...
       (*h)->DrawClone();
    }
}

void read_v2(){
     // Compact, more performant version with C++ callables
     class idFilter {
     private:
        int fId;
     public:
        idFilter(int id) : fId(id) {}
        bool operator()(int id) { return id == fId; }
     };
     auto df         = ROOT::RDataFrame("myTree", "myFile.root");
     auto df0        = df.Filter(idFilter(0), {"idEvent"});
     auto h_time_0   = df0.Histo1D<std::vector<float>>({"ht0","time idEvent = 0",64,0,100}, "time");
     auto h_energy_0 = df0.Histo1D<std::vector<float>>({"he0","energy idEvent = 0",64,0,100}, "energy");
     auto df1        = df.Filter(idFilter(1), {"idEvent"});
     auto h_time_1   = df1.Histo1D<std::vector<float>>({"ht1","time idEvent = 1",64,0,100}, "time");
     auto h_energy_1 = df1.Histo1D<std::vector<float>>({"he1","energy idEvent = 1",64,0,100}, "energy");
     // ... and so on.

    for (auto &&h : {&h_time_0, &h_time_1, &h_energy_0, &h_energy_1}) {
       new TCanvas(); // this stays after the function returns...
       (*h)->DrawClone();
    }
}


void test(){
    write();
    read_v1();
    read_v2();
}

Thank you very much. But only the last histogram is written .

i used ,

TFile *outputFile = new TFile(outFilename.c_str(),"RECREATE");
        std::cout << "Output file written to " << outFilename << std::endl;

        for (idEvent>=0 ; idEvent<=8;idEvent++){

        peakno[idEvent]->Write();
        intno[idEvent]->Write();

in the last. I can not understand where exactly i put the loop for them.

Thank you very much.

I can not write peakno[i] . I am trying to get peakno[1] , peakno[2] , peakno[3], …upto peakno[8]. If i write the spectra at last i am only getting peakno[8].Could you help ?

thank you.

Post the (complete) code you have now.

Please find the attached code.

#include <string>
#include <sstream>
#include <fstream>
#include <unistd.h>
#include <stdlib.h>
#include <algorithm>

#include "struct.h"
#include "ReadGDML.h"
#include "ReadEDepSim.h"
#include "ReadOptical.h"
#include "ReadDigit.h"
#include "CameraImage.h"
#include "FastFitter.h"
#include "LensDisplayer.h"
#include "LineIntersector.h"
#include "StructDefinition.h"
#include "TrackMatcher.h"
#include "Volume3DReconstructer.h"
#include "EnergyEstimator.h"
#include "TFile.h"
#include "TTree.h"
#include "TMath.h"
#include "TApplication.h"
#include "TF1.h"
#include "TH2I.h"
#include "TCanvas.h"
#include "TVector3.h"
#include "TH1.h"
#include "TRandom.h"
#include "TSpectrum.h"
#include "TChain.h"
#include "TVirtualFitter.h"
#include "Riostream.h"
Int_t npeaks=10 ;
Int_t final_nfound;
Int_t final_nfound1;
Int_t A;
Int_t B;
Int_t t;
float taufast=6e-9;
float tauslow=1.6e-6;

void usage() {

        std::cout << "Input parameters needed: " << std::endl;
        std::cout << "-i 'root file with spill data '" << std::endl;
        std::cout << std::endl;
}
        int main(int argc, char **argv) {

        std::string inFilename="";
        std::string outFilename="";
        int iflag=0, oflag=0; //mandatory
        int opt;
        outFilename = "interaction.root";
               while( (opt = getopt(argc, argv, "i:o")) != -1) {
                switch(opt) {
                        case 'o':
                                if(optarg) outFilename = optarg;
                                oflag = 1;
                                break;

                        case 'i':
                                if(optarg) inFilename = optarg;
                                iflag = 1;
                                break;

                        default:
                                usage();
                                return 1;
                }
        }

        if(!iflag) {

                std::cout << "ERROR: missing REQUIRED parameters!" << std::endl;
                usage();
                return 1;

        }

        std::cout << "Sensor file: " << inFilename << std::endl;
        std::cout << "Output file: " << outFilename << std::endl;

        std::cout << "*****************************************************" << std::endl;

        std::cout << "Reading data" << std::endl;

        // open file

        TFile *m_f = new TFile(inFilename.c_str(), "READ");
        if (!m_f) {

                std::cout << "ERROR: missing the file!" << std::endl;

        }
Int_t k;
       TChain *tree = new TChain();
       for (int k=1;k<39;k++){

               tree->Add(Form("./%s/CAM_%d",inFilename.c_str(),k));

       }
        if (!tree) {
                std::cout << "ERROR: missing the event trees!" << std::endl;
        }

        Int_t idEvent;
        std::vector<double> *energy=0 ;
        std::vector<double> *time=0 ;

        tree->SetBranchAddress("time", &time);
        tree->SetBranchAddress("idEvent",&idEvent);
        tree->SetBranchAddress("energy",&energy);
        const int n=9;
        TH1F *peakno[n];
        TH1F *intno[n];
        for (int i=0;i<n;i++){
         peakno[i] = new TH1F(Form("peakno%d",i),Form("peakno%d",i),20000,0,20000);
         intno[i] = new TH1F(Form("intno%d",i),Form("intno%d",i),100,0,100);
        }

        int N = tree->GetEntries();
        for (int i=0; i<N; i++)

        {
                tree->GetEntry(i);
                ULong_t nsig = time->size();
                double *sig = time->data();
                double *esig = energy->data();

         if (idEvent>=0 && idEvent<=8){
              for (ULong_t j=0; j<nsig; j++){
              peakno[idEvent]->Fill(sig[j]);

                }

         }

        }

                        if (idEvent>=0 && idEvent <=8){
                        TSpectrum *s = new TSpectrum(npeaks);
                        Int_t nfound = s->Search(peakno[idEvent],0.0,"",0.1);
                        std::cout << "no of peaks = " << nfound << std::endl;
                        intno[idEvent]->Fill(nfound);

         }

        TFile *outputFile = new TFile(outFilename.c_str(),"RECREATE");
        std::cout << "Output file written to " << outFilename << std::endl;

        if (idEvent>=0 && idEvent <=8){
        peakno[idEvent]->Write();
        intno[idEvent]->Write();

        outputFile->Close();

        }

}

Thank you.

I fixed your code as much as I could (I cannot run it because I do not have your data file). I also intended your code. Please keep it that way. It is much easier to read.

#include <string>
#include <sstream>
#include <fstream>
#include <unistd.h>
#include <stdlib.h>
#include <algorithm>

#include "struct.h"
#include "ReadGDML.h"
#include "ReadEDepSim.h"
#include "ReadOptical.h"
#include "ReadDigit.h"
#include "CameraImage.h"
#include "FastFitter.h"
#include "LensDisplayer.h"
#include "LineIntersector.h"
#include "StructDefinition.h"
#include "TrackMatcher.h"
#include "Volume3DReconstructer.h"
#include "EnergyEstimator.h"
#include "TFile.h"
#include "TTree.h"
#include "TMath.h"
#include "TApplication.h"
#include "TF1.h"
#include "TH2I.h"
#include "TCanvas.h"
#include "TVector3.h"
#include "TH1.h"
#include "TRandom.h"
#include "TSpectrum.h"
#include "TChain.h"
#include "TVirtualFitter.h"
#include "Riostream.h"
int npeaks=10 ;
int final_nfound;
int final_nfound1;
int A;
int B;
int t;
float taufast=6e-9;
float tauslow=1.6e-6;

void usage() {
   std::cout << "Input parameters needed: " << std::endl;
   std::cout << "-i 'root file with spill data '" << std::endl;
   std::cout << std::endl;
}

int main(int argc, char **argv) {

   std::string inFilename="";
   std::string outFilename="";
   int iflag=0, oflag=0; //mandatory
   int opt;
   outFilename = "interaction.root";

   while( (opt = getopt(argc, argv, "i:o")) != -1) {
      switch (opt) {
         case 'o':
            if(optarg) outFilename = optarg;
            oflag = 1;
            break;

         case 'i':
            if(optarg) inFilename = optarg;
            iflag = 1;
            break;

         default:
            usage();
            return 1;
      }
   }

   if (!iflag) {
      std::cout << "ERROR: missing REQUIRED parameters!" << std::endl;
      usage();
      return 1;
   }

   std::cout << "Sensor file: " << inFilename << std::endl;
   std::cout << "Output file: " << outFilename << std::endl;
   std::cout << "*****************************************************" << std::endl;
   std::cout << "Reading data" << std::endl;

   // open file
   TFile *m_f = new TFile(inFilename.c_str(), "READ");
   if (!m_f) {
      std::cout << "ERROR: missing the file!" << std::endl;
   }

   int k;
   TChain *tree = new TChain();
   for (int k=1;k<39;k++){
      tree->Add(Form("./%s/CAM_%d",inFilename.c_str(),k));
   }

   if (!tree) {
      std::cout << "ERROR: missing the event trees!" << std::endl;
   }

   int idEvent;
   std::vector<double> *energy=0 ;
   std::vector<double> *time=0 ;

   tree->SetBranchAddress("time", &time);
   tree->SetBranchAddress("idEvent",&idEvent);
   tree->SetBranchAddress("energy",&energy);

   const int n=9;
   TH1F *peakno[n];
   TH1F *intno[n];

   for (int i=0;i<n;i++) {
      peakno[i] = new TH1F(Form("peakno%d",i),Form("peakno%d",i),20000,0,20000);
      intno[i]  = new TH1F(Form("intno%d",i),Form("intno%d",i),100,0,100);
   }

   int N = tree->GetEntries();
   
   for (int i=0; i<N; i++) {
      tree->GetEntry(i);
      ULong_t nsig = time->size();
      double *sig  = time->data();
      double *esig = energy->data();

      if (idEvent>=0 && idEvent<=8) {
         for (ULong_t j=0; j<nsig; j++) {
            peakno[idEvent]->Fill(sig[j]);
         }
      }
   }

   for (int i=0;i<n;i++) {
      TSpectrum *s = new TSpectrum(npeaks);
      int nfound = s->Search(peakno[i],0.0,"",0.1);
      std::cout << "no of peaks = " << nfound << std::endl;
      intno[i]->Fill(nfound);
   }

   TFile *outputFile = new TFile(outFilename.c_str(),"RECREATE");
   std::cout << "Output file written to " << outFilename << std::endl;

   for (int i=0;i<n;i++) {
      peakno[i]->Write();
      intno[i]->Write();
   }

   outputFile->Close();
}

Also, you might also want to try @Danilo suggestion.

Thanks Both!
The example of Olivier, well written, made me condense further the code I had.
Here you can find it:

    class idFilter {
    private:
       int fId;
    public:
       idFilter(int id) : fId(id) {}
       bool operator()(int id) { return id == fId; }
    };
    using RPtrHist = ROOT::RDF::RResultPtr<::TH1D>;
    std::vector<RPtrHist> energy_histos;
    std::vector<RPtrHist> time_histos;

    auto df = ROOT::RDataFrame("myTree", "myFile.root");
    
    for (auto i : ROOT::TSeqI(8)) {
     auto iStr = std::to_string(i);
     auto filtered_df = df.Filter(idFilter(i), {"idEvent"});
     time_histos.emplace_back(filtered_df.Histo1D({"ht","time idEvent",64,0,100}, "time"));
     energy_histos.emplace_back(filtered_df.Histo1D({"he","energy idEvent = ",64,0,100}, "energy"));
    }

    TFile outFile("outFile.root","RECREATE");
    for (auto &&h : time_histos) {
       h->Write();
    }
    for (auto &&h : energy_histos) {
       h->Write();
    }

Thank you very much sir. I will run it .

yes, I will try danillo’s code also. I know little about programming . Danillo’s code is looking tough.

thank you.

Thank you very much sir. It is little difficult for me to understand as I do not good coding. I will try this also.

with calm, no worries, only if it helps!
D

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.