Creating, filling and saving histograms in a loop

Hi,

I’m trying to run over an ntuple and produce histograms for every single detector component, something like 400000 histograms. So in a loop over events, then tracks, then hits I get elementId, which goes from 1 to 400000. I use it to create a name for my histogram

TObjArray HList(0);

char histoname[200]={ };
strcat(histoname, "h_element_");
sprintf(elementIdAsCharArray, "%d", (*elementId).at(trackIt).at(hitIt));
strcat(histoname, elementIdAsCharArray.c_str());
TH1F * myhist = new TH1F(histoname,"Response time;t[ns];Number of hits",300,0.,30.);

, then fill it and add to the TObjArray

myhist->Fill(time,1.); 
HList.Add(myhist);

After all loops are finished, I save my TObjArray into a .root file:

HList.Write();

Here is the problem: in case in the loop there was only one entry to a particular histogram, that’s fine. But when there are two or more, a histogram will be replaced by the new one and I’ll get only one last value.
How do I avoid it? The problem seems to be that the constructor is inside the loop? But is there any way I can get it outside if I cannot create histogram name before I get this particular hit to know detector element ID which goes into histoname?
Any help will be appreciated, thanks!

[code] TObjArray HList(0);

for (loop over events, elements, tracks, hits)
{
TString histoname =
TString::Format(“h_element_%d”, (*elementId).at(trackIt).at(hitIt));

  TH1F *myhist = ((TH1F *)(HList.FindObject(histoname)));
  if (!myhist)
    {
      myhist = new TH1F(histoname,
                        "Response time;t[ns];Number of hits",
                        300, 0., 30.);
      HList.Add(myhist);
    } // if (!myhist) ...
  
  myhist->Fill(time, 1.);
} // for (loop over events, elements, tracks, hits) ...

HList.Write();[/code]

If you can guarantee that:
0 <= (*elementId).at(trackIt).at(hitIt) <= SomeReasonableMaxValue
(the “HList” total RAM usage will be about “(1 … 2) * SomeReasonableMaxValue * sizeof(a_pointer)”)
then try a much much faster solution: [code] TObjArray HList(0);

for (loop over events, elements, tracks, hits)
{
// Note: you must be sure that 0 <= index <= SomeReasonableMaxValue
// because the “HList” total RAM usage will be about
// (1 … 2) * SomeReasonableMaxValue * sizeof(a_pointer)
Int_t index = (*elementId).at(trackIt).at(hitIt);
if (index < 0) continue; // just a precaution

  TH1F *myhist = ((TH1F *)0);
  if (index < HList.GetSize()) myhist = ((TH1F *)(HList.At(index)));
  if (!myhist)
    {
      myhist = new TH1F(TString::Format("h_element_%d", index),
                        "Response time;t[ns];Number of hits",
                        300, 0., 30.);
      HList.AddAtAndExpand(myhist, index);
    } // if (!myhist) ...
  
  myhist->Fill(time, 1.);
} // for (loop over events, elements, tracks, hits) ...

HList.Write();[/code]

Hi Wile E. Coyote,

Tried your first suggestion, works like a charm, thank you so much! And thanks for the second one, hope to test it sometime later!