Modifiying the value of an existing leaf

I would like to modify the value of an existing leaf, the same value for each of the events (this is for a Monte Carlo weighting). I can add the leaf but I am apparently doing something wrong for the modification. The number of entries in the branch increase but the it seems that the values are not updated. I have attached my sample code (and the test datafile) … (Ok, well it is the program to do the addition but I felt that it was small enough) Thanks for any help.

To reproduce run the following commands:

./modifyLeaf --add --leafname=testleaf --value=10
./modifyLeaf --print --leafname=testleaf
./modifyLeaf --add --leafname=testleaf --value=12
./modifiyLeaf --print --leafname=testleaf

Justace
theskim.root (163 KB)

for some reason it would not let me have more than one attachement to the post… here is the code… Ok, it will just not let me do this… I guess I will cut/paste (sorry for this)

#include <TFile.h>
#include <TTree.h>
#include <TLeaf.h>
#include <TBranch.h>
#include <iostream>
#include <string>
#include <getopt.h>

using namespace std;

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

  // Get the options from the command line

  int c;
  static int add_flag    = 0;
  static int remove_flag = 0;
  static int print_flag  = 0;

  string leaf_name       = "";
  double leaf_value      = 0;
  string leaf_type       = "Double_t";
  string filename        = "theskim.root";
  string tree_name       = "skim";
  string open_option     = "";

  Double_t double_type;
  Int_t    int_type;

  static struct option long_options[] = {
    {"add", 0, &add_flag, 1},		// 0
    {"remove", 0, &remove_flag, 1},	// 1
    {"print", 0, &print_flag, 1},	// 2
    {"leafname", 1, 0, 0},		// 3
    {"leaftype", 1, 0, 0},		// 4
    {"value", 1, 0, 0},			// 5
    {"filename", 1, 0, 0},		// 6
    {"treename", 1, 0, 0},		// 7
    {0, 0, 0, 0}
  };

  while (1) {

    /* getopt_long stores the option index here. */
    int option_index = 0;

    c = getopt_long (argc, argv, "", long_options, &option_index);

    /* Detect the end of the options. */
    if (c == -1)
      break;

    switch (c) {
      case 0:
        switch(option_index) {
          case 3:
            leaf_name = string(optarg);
            break;
          case 4:
            leaf_type = string(optarg);
            break;
          case 5:
            leaf_value = atof(optarg);
            break;
          case 6:
            filename = string(optarg);
            break;
          case 7:
            tree_name = string(optarg);
            break;
        }

        break;

      case '?':
        /* getopt_long already printed an error message. */
        break;

      default:
        abort ();
      }
  }

  int op_count = 0;
  if(add_flag)    op_count++;
  if(remove_flag) op_count++;
  if(print_flag)  op_count++;

  if(op_count > 1) {
    cout << "Can not select more than one operation\n";
    return(1);
  }

  if(add_flag || remove_flag) open_option = "UPDATE";

  // Open the file, get the tree and make sure everything is in good order

  TFile input(filename.c_str(), open_option.c_str());

  if(input.IsOpen() != kTRUE) {
    cout << "Could not open file " << filename << endl;
    exit(1);
  }

  TTree *tree = (TTree*) input.Get(tree_name.c_str());

  // See if the tree exists...

  if(tree == 0x0) {
    cout << "Error: The tree named " << tree_name.c_str() << " does not exist in file " << filename << endl;
    input.Close();
    exit(1);
  }

  bool fail = false;

  if(add_flag) {
    if(leaf_name.size() == 0) {
      cout << "Must set the leaf name\n";
      fail = true;
    }

    if(!fail) {
      // Needed variables for this section of the code

      TBranch *tbranch = 0x0;

      // See if the leaf exists already...  (if it does then we just modify it)

      TLeaf *tleaf = tree->FindLeaf(leaf_name.c_str());

      if(tleaf == 0x0) {
        // ok, the leaf does not exist, lets make it...

        if(leaf_type == "Double_t") {
          tbranch = tree->Branch(leaf_name.c_str(), &double_type, (leaf_name + "/D").c_str());
        } else if(leaf_type == "Int_t") {
          tbranch = tree->Branch(leaf_name.c_str(), &int_type, (leaf_name + "/I").c_str());
        }
      } else {
        // The leaf already exsisted, so lets setup to modify it...

        tbranch = tree->GetBranch(leaf_name.c_str());

        if(tbranch == 0x0) {
          cout << "Unable to find the branch to modifiy it" << endl;
          input.Close();
          exit(1);
        }

        tbranch->Print();
      
        if(leaf_type == "Double_t") {
          tbranch->SetAddress(&double_type);
        } else if(leaf_type == "Int_t") {
          tbranch->SetAddress(&int_type);
        }
      }

      if(tbranch == 0x0) {
        cout << "Branch creation failed for branch name " << leaf_name << " in tree " << tree_name << " in file " << filename << endl;
        input.Close();
        exit(1);
      }

      // Loop over all the events in the file

      for(long i = 0; i < tree->GetEntries(); i++) {
        tree->GetEntry(i);

        // Set the value

        if(leaf_type == "Double_t") {
          double_type = leaf_value;
        } else if(leaf_type == "Int_t") {
          int_type = int(leaf_value);
        }

        tbranch->Fill();
      }      

      tree->Write("",TObject::kOverwrite);
    }
  }

  if(print_flag) {
    // Get the leaf

    TLeaf *tleaf = tree->FindLeaf(leaf_name.c_str());

    if(tleaf == 0x0) {
      cout << "Could not find the leaf named " << leaf_name << endl;
      input.Close();
      exit(1);
    }

    for(long i = 0; i < tree->GetEntries(); i++) {
      tree->GetEntry(i);

      cout << i << ": " << tleaf->GetValue() << endl;
    }
  }

  input.Close();

  return(0);

}

Hi,

The issue is most likely the fact that you (seem to) use the same name for the old and new leaf and hence doingTLeaf *tleaf = tree->FindLeaf(leaf_name.c_str());retrives the old one. Try with a different leaf name.

Cheers,
Philippe.

If I have a different name then I have to change all my code to use that new name… I just want to change the values of the leafs that are stored… Is it possible to remove the leaf and then re-add it?

Justace

Hi,

No removing and adding the same leaf to the same TTree is not supported.
Instead we recommend that you create a new copy of the TTree with the corrected leaf. For example: TFile input(filename.c_str(), open_option.c_str()); ... TTree *tree = (TTree*) input.Get(tree_name.c_str()); ... TFile output(outfilename.c_str(), open_out_option.c_str()); ... TTree *outtree = tree->CloneTree(0); ... if(leaf_type == "Double_t") { tree->SetBranchSetAddress(leaf_name.c_str(),&double_type); outtree->SetBranchSetAddress(leaf_name.c_str(),&double_type); } else if(leaf_type == "Int_t") { tree->SetBranchSetAddress(leaf_name.c_str(),&int_type); outtree->SetBranchSetAddress(leaf_name.c_str(),&int_type); } } .... for(long i = 0; i < tree->GetEntries(); i++) { tree->GetEntry(i); .... outtree->Fill(); } ... outtree->Write(...);

Cheers,
Philippe.