Home | News | Documentation | Download

ROOT states the directory not writable even though it was opened with "UPDATE"

Hello there! This is my first post here so thank you for the attention. Now, on to the problem at hand.

I’m currently trying to draw a series of histograms. To do so, I defined a function Createf90Dist
, which I proceed to call numerous times inside a for loop. I then write the histograms in the desired file. Here’s a snippet of my code indicating what exactly is being done:

Createf90Dist(...){
  const char *previous_dir = gDirectory -> GetPath();

  TFile *file = new TFile(file_name); // opens the file with the desired data.

  //make the histogram named f90_dist
  // ...

  f90_dist -> SetDirectory(0);
  file -> Close();

  gDirectory -> cd(previous_dir); // return to the previous directory
  return f90_dist;
}

Then, in the main code, I call the function in the following way:

TFile *hist_file = new TFile(Form("hist_%d.root", run), "UPDATE");

  for (int j = 0; j < number_divisions; j++){
      if (i == 0){
        data_dir -> cd(); 
        f90hist_run[j] = Createf90Dist(Form("run_%d%s.root", run, file_suffix[i].c_str()), max_charge[i], 0., 1., number_divisions, j+1);
        f90hist_run[j] -> SetName(Form("f90_distribution%d", j));
        f90hist_run[j] -> SetTitle("f90 Distribution; f90");

        f90hist_run[j] -> Write(Form("f90_distribution%d", j), TObject::kOverwrite);
      }
  }

were data_dir is a subfolder inside the hist_file. When I check wether the current directory after calling the function is the desired one (data_dir) using gDirectory -> pwd() it returns the correct one. However, when actually loading the macro and running it, ROOT returns the following:

Error in <TDirectoryFile::WriteTObject>: Directory hist_1220.root is not writable

Note: if I, after calling the function, manually change the directory to the desired one, the code runs smoothly. I just wanted to see if there was a way of me including this step withing the function definition, as I believe I have attempted.


ROOT Version: 6.16.00
Platform: Ubuntu 18.04.3 LTS
Compiler: Not Provided


I think @pcanal can help you.

I am not sure why this does not work, I would need a reproducer. However there is several ways to improve the code.

const char *previous_dir = gDirectory -> GetPath();

rather than the “name” of the directory you could record the pointer value

auto previous_dir = gDirectory;
... 
previous_dir->cd();

There is also a construct to do this automatically (in one line)

TDirectory::TContext ctxt; // Will capture the current directory at construction and go back to it at destruction

Also you could simply ignore the current directory value and replace

f90hist_run[j] -> Write(Form("f90_distribution%d", j), TObject::kOverwrite);

with

data_dir->WriteObject( f90hist_run[j], Form("f90_distribution%d", j), TObject::kOverwrite);

Cheers,
Philippe.

Hello Philippe! Thank you for the quick answer and I apologize for taking so long to reply.

I attempted your fix, and rewrote the original code to the following:

data_dir->WriteObject( f90hist_run[j], Form("f90_distribution%d", j), TObject::kOverwrite);

However, doing so resulted in the following error:

error: no matching member function for call to 'WriteObject'
note: candidate function not viable: no known conversion from 'TObject::(anonymous enum at /home/miguel/Desktop/Mestrado/ROOT/root/include/TObject.h:86:4)' to 'Option_t *' (aka 'const char *') for 3rd argument
   template <class T> inline Int_t WriteObject(const T* obj, const char* name, Option_t *option="", Int_t bufsize=0) // see TDirectory::WriteTObject or TDirectoryWriteObjectAny for explanation
note: candidate function not viable: no known conversion from 'TObject::(anonymous enum at /home/miguel/Desktop/Mestrado/ROOT/root/include/TObject.h:86:4)' to 'Option_t *' (aka 'const char *') for 3rd argument
           Int_t       WriteObject(void *obj, const char* name, Option_t *option="", Int_t bufsize=0); // Intentionaly not implemented.

Also: I’m quite new at this, so what exactly do you mean when you mention that you would “need a reproducer”?

Thank you very much for your attention,
Miguel.

It means that you would to provide enough information (full source files, command lines, input data file), so that I can reproduce the problem you seen exactly and without any guessing.

My apologies, I had typos in the text, I meant:

data_dir->WriteObject( f90hist_run[j], Form("f90_distribution%d", j), "OverWrite");

i.e. those interface have not yet been upgrade to use the enum.

Cheers,
Philippe.

I understand what you mean by “reconstruction” now. Thank you for being so clear!

I corrected the typo you mentioned. The code now runs smoothly.

Thank you for your help!
Miguel.