Subdirectories

Hello
I am trying to create a subdirectory ( a directory inside another directory) and write data to it. I am not sure what i am doing wrong:

  TFile *file = fChain->GetCurrentFile();

  file->cd();
  file->mkdir("Thermal/");
  file->cd("Thermal/");
  AnalysisResultTuple.Write("",TObject::kOverwrite);

  file->cd();
  file->mkdir("Thermal/Zdepth");
  file->cd("/Thermal/Zdepth/");
  thermal_depthSlicesHist->Write("",TObject::kOverwrite);
  thermal_depthSliceEkinHist->Write("",TObject::kOverwrite);
  thermal_depthSliceEdepHist->Write("",TObject::kOverwrite);

Using a TBrowser, files are not written in the proper subdirectory. They are written at the file.root:/ level directory. What am I doing wrong??

Thxs,

Right before doing “Something->Write(…);”, try to call “Something->SetDirectory(gDirectory);”

Great Thanks. However, TObjArrays do not have that method? Is there any other way to set the directory before writing objects?

I’m afraid you need to loop over all objects from your TObjArray and for each of them call “SetDirectory(gDirectory)”.

Maybe a better solution would be to make sure that all histograms are “associated” with “gROOT” or with “nothing” at their creation time. Before you call “new Something(…)” make sure that you “gROOT->cd();”, or after you call “new Something(…)” make sure that you call “SetDirectory(gROOT)” or “SetDirectory(0)” for this newly created object.
You could also execute the static method TDirectory::AddDirectory(kFALSE); in advance, before you create any histograms (then there’s no need to call “SetDirectory(0)” for them).
BTW. If an object / class has no “SetDirectory” method then you don’t need to care about it at all, I believe (unless it’s a “container” which keeps objects which do have this method, of course).

Actually I did not have to loop through the TObjArray elements. As a matter of fact, I did not have to use the SetDirectory method either. This is what I did. There are two sections. One where I create all my dir hierarchy:

 file->cd();
  gDirectory->mkdir("Thermal");
  file->cd("Thermal");
  gDirectory->mkdir("Zdepth");

  file->cd();
  file->cd("Thermal");
  gDirectory->mkdir("rSlices");

  file->cd();
  gDirectory->mkdir("nFission");
  file->cd();

and then before I call any write method, I set the directory where the objects were going to be stored:

  file->cd();
  file->cd("Thermal");
  AnalysisResultTuple.Write("",TObject::kOverwrite);  //A TH1F* object

  thermal_depthSlicesHist->Write("",TObject::kOverwrite);   //A TH1F* object
  thermal_gTime->Write("",TObject::kOverwrite);                   //A TH1F* object
  thermal_gTimeCONV->Write("",TObject::kOverwrite);        //A TH1F* object

  file->cd();
  file->cd("Thermal/Zdepth");
  thermal_depthSliceEkinHist->Write("",TObject::kOverwrite);  //A TObjArray* object
  thermal_depthSliceEdepHist->Write("",TObject::kOverwrite); //A TObjArray* object

I hope this help some programmer soul out there.
Cheers,

You are right. I got confused by something else, sorry.
However, I don’t really understand then why you got problems with the source code from your first post here. On second thought, I see no problem in it (there should be no real difference with respect to the source code from your last post here).

The problem I was having boiled down to the function mkdir. In my first post, it was not creating the folders and all my objects were stored in the root (Top) directory. Then after doing some browsing I changed my statement file->mkdir(…) to gDirectory->mkdir(…) and everything worked as a charm. At the same time I had already included in my code the setDirectory to my TH1 objects. After few trials and errors, I just realized I have to set my folder right before I save (write) my objects and nothing more. Your comments were very appreciated though.
Iin a nutshell, I don’t know why mkdir didn’t work in the first place. Interesting enough, initially I tried a combination of mkdir() and cd() commands in different funny orders to see if I could make it work and the last thing that worked was the gDirectory call.

C’est la vie I guess.
Cheers,

I created a small “test case” which contains a “copy” your “original” source code … [code]{
TFile *file = TFile::Open(“trial.root”, “RECREATE”);

TNtuple *AnalysisResultTuple = new TNtuple(“AnalysisResultTuple”, “AnalysisResultTuple”, “x”);
TH1F *thermal_depthSlicesHist = new TH1F(“thermal_depthSlicesHist”, “thermal_depthSlicesHist”, 100, 0, 1);
TH1F *thermal_gTime = new TH1F(“thermal_gTime”, “thermal_gTime”, 100, 0, 1);
TH1F *thermal_gTimeCONV = new TH1F(“thermal_gTimeCONV”, “thermal_gTimeCONV”, 100, 0, 1);
TH1F *thermal_depthSliceEkinHist = new TH1F(“thermal_depthSliceEkinHist”, “thermal_depthSliceEkinHist”, 100, 0, 1);
TH1F *thermal_depthSliceEdepHist = new TH1F(“thermal_depthSliceEdepHist”, “thermal_depthSliceEdepHist”, 100, 0, 1);

file->cd();
file->mkdir(“Thermal/”);
file->cd(“Thermal/”);
AnalysisResultTuple->Write("",TObject::kOverwrite);

file->cd();
file->mkdir(“Thermal/Zdepth”);
file->cd("/Thermal/Zdepth/");
thermal_depthSlicesHist->Write("",TObject::kOverwrite);
thermal_depthSliceEkinHist->Write("",TObject::kOverwrite);
thermal_depthSliceEdepHist->Write("",TObject::kOverwrite);

delete file;
}[/code] and I see no problem with it … all subdirectories are created as expected …
After executing this “test case”, you can try: root [0] TFile *file = TFile::Open("trial.root", "READ"); root [1] gDirectory->ls(); TFile** trial.root TFile* trial.root KEY: TDirectoryFile Thermal;1 Thermal/ root [2] gDirectory->cd("Thermal"); root [3] gDirectory->ls(); TDirectoryFile* Thermal Thermal/ KEY: TNtuple AnalysisResultTuple;1 AnalysisResultTuple KEY: TDirectoryFile Zdepth;1 Zdepth root [4] gDirectory->cd("Zdepth"); root [5] gDirectory->ls(); TDirectoryFile* Zdepth Zdepth KEY: TH1F thermal_depthSlicesHist;1 thermal_depthSlicesHist KEY: TH1F thermal_depthSliceEkinHist;1 thermal_depthSliceEkinHist KEY: TH1F thermal_depthSliceEdepHist;1 thermal_depthSliceEdepHist root [6] file->ls(); TFile** trial.root TFile* trial.root TDirectoryFile* Thermal Thermal/ TDirectoryFile* Zdepth Zdepth KEY: TH1F thermal_depthSlicesHist;1 thermal_depthSlicesHist KEY: TH1F thermal_depthSliceEkinHist;1 thermal_depthSliceEkinHist KEY: TH1F thermal_depthSliceEdepHist;1 thermal_depthSliceEdepHist KEY: TNtuple AnalysisResultTuple;1 AnalysisResultTuple KEY: TDirectoryFile Zdepth;1 Zdepth KEY: TDirectoryFile Thermal;1 Thermal/ root [7] .q

The only thing it was different to your example is that I am using CINT to compile. That shouldn’t make a big difference, right?

Maybe all my ordeal is because I try so many things at once before i got to the working version. The solution came to me after I looked at the following post:

Cheers,

Just for reference … I tried your “original” source code as an ACLiC (pre)compiled macro (I modified my small “test case”) and I still see no problem with it.

Hello!

I realise this post is quite old but it helped me understand why my directory structure was not working now 7 years later and I wanted to add my findings.

What caused the problems with mkdir for me is shown with the following code:

//create test file
TFile *outFile = new TFile("dirTest.root","RECREATE");
//create test dir
TDirectory* d = outFile->mkdir("test");
//check if returned pointer points to test dir
std::cout << "test: " << d << ", " << d->GetName() << std::endl;
//move to test dir
d->cd();
std::cout << "Tried to move to test, moved to: " << gDirectory->GetDirectory(0)->GetPath() << std::endl;
//make test2 subdir
TDirectory* d2 = outFile->mkdir("test/test2");
//check if returned pointer points to test2 subdir
std::cout << "test2: " << d2 << ", " << d2->GetName() << std::endl;
//try to move to test2 subdir
d2->cd();
std::cout << "Tried to move to test2, moved to: " << gDirectory->GetDirectory(0)->GetPath() << std::endl;
//rebase (because paths in cd() are relative) and move to test2 subdir via gDirectory and explicit path
outFile->cd();
gDirectory->cd("test/test2");
//check location again
std::cout << "test2: " << gDirectory->GetDirectory(0) << ", " << gDirectory->GetDirectory(0)->GetName() << std::endl;
std::cout << "Tried to move to test2 via gDirectory and path, moved to: " << gDirectory->GetDirectory(0)->GetPath() << std::endl;

The output is then:

test: 0x4fa7e30, test
Tried to move to test, moved to: dirTest.root:/test
test2: 0x4fa7e30, test
Tried to move to test2, moved to: dirTest.root:/test
test2: 0x4c5b900, test2
Tried to move to test2 via gDirectory and path, moved to: dirTest.root:/test/test2

In the second mkdir call the sub-directory is created, but a pointer to the mother directory is returned. We can see this from the literal pointer being the same and from the output. Would it not make more sense if “mkdir” returned a pointer to the actually created directory? This would allways be the last directory in a hierarchy “a/b/c/…” anyway and no undefined behavior should result, right? And if that sub-directory cannot be created, return 0 and a warning?

Cheers,
Florian

Hello @_Badger,

normally, I would now have said “let’s not warm up such an old topic”. But here, you are right, it’s good for the context.
I would ask @pcanal to comment on the pointer being returned.

You are right. See https://github.com/root-project/root/pull/5264.

thanks.

The problem is fixed in the master.

Thanks,
Philippe.