Fill 'nan' or empty value for an entry

Hi.
I am trying to add a new Branch in a given TTree.
For example, I have a tree with 50 entries. I want to add another branch in this tree so that only the first 10 entries have some values, and the remaining 40 entries are filled empty or ‘nan’ (p.s. I don’t want to fill those with 0).
How can this be achieved?

Following is a code snippet of what I tried, but couldn’t achieve.

// Defining a class                                                                                
 class Big  { 
     public: ULong64_t x;
             ULong64_t y;
}; 
                                                                                                                                                                                      
void treeAddBranch()
{                                                       
    TFile f("file.root", "update");
    auto t = f.Get<TTree>("OutputTree");            
    ULong64_t nentries = t->GetEntries();

    Big big;    
    TBranch *gb1 = t->Branch("Big", "big", &big);                                                                                                                                                           
    
    //Fill some entries with some values
    for (ULong64_t i = 0; i < 10; i++)  
    {                               
        big.x = i*1;
        big.y = i*2;   
        t->Fill(); 
    }                                                                                                                                                                                                       
    //Fill remaining entries with 'nan'
    ULong64_t nanValue = std::nan("");
    for (ULong64_t i = 10; i < nentries; i++)
    {                                                       
       big.x = nanValue;    
       big.y = nanValue;          
       t->Fill();
    }
                                                                                                                                                                                                       
    t->Write("", TObject::kOverwrite); // save only the new version of the tree
    printf("A branch in 'file.root' file is added successfully.\n");
}              

ROOT Version: 6.26/10
Platform: Ubuntu 22.04.2 LTS


Hello,

Thanks for the interesting post and welcome to the ROOT Community!
Could you be perhaps a bit more precise about the problem you are facing? What did not work?

Cheers,
D

Thanks for the reply.

Lets say ‘Wide.a’ and ‘Wide.b’ are the branches that were already present.
‘Big.x’ and ‘Big.y’ are the new branch I want to add.

With my code mentioned above, following is obtained.

OutputTree->Scan("Wide.a : Wide.b : Big.x : Big.y")

***********************************************************************
*    Row   * Instance * Wide.a    * Wide.b        * Big.x     * Big.y *
***********************************************************************
*        0 *        0 * 56.877945 * 56.137086 *         0 *         0 *
*        0 *        1 * 58.238992 *           *         0 *         0 *
*        0 *        2 * 150.36524 *           *         0 *         0 *
*        1 *        0 * 45.653616 * 69.914696 *         1 *         2 *
*        1 *        1 * 45.532576 *           *         1 *         2 *
*        2 *        0 * 49.053735 * 114.21307 *         2 *         4 *
*        3 *        0 *           * 44.001037 *         3 *         6 *
*        4 *        0 * 223.79526 *           *         4 *         8 *
*        5 *        0 * 103.84502 * 45.861062 *         5 *        10 *
*        6 *        0 * 56.055652 * 44.635575 *         6 *        12 *
*        6 *        1 * -10032.92 *           *         6 *        12 *
*        7 *        0 * 49.811174 *           *         7 *        14 *
*        8 *        0 * 45.785648 * 129.48804 *         8 *        16 *
*        9 *        0 * 46.765646 *           *         9 *        18 *
*       10 *        0 * 35.704076 * 21.099606 * 9.223e+18 * 9.223e+18 *
*       10 *        1 * 221.39279 *           * 9.223e+18 * 9.223e+18 *
*       11 *        0 * 40.141002 * 38.429454 * 9.223e+18 * 9.223e+18 *
*       11 *        1 * 29.690747 * 32.389832 * 9.223e+18 * 9.223e+18 *
*       12 *        0 *           * 30.231115 * 9.223e+18 * 9.223e+18 *
*       13 *        0 * 111.39832 * 299.24426 * 9.223e+18 * 9.223e+18 *
*       13 *        1 * 81.730985 * 117.39984 * 9.223e+18 * 9.223e+18 *

A. The Fill method fills data in ‘Big.x’ and ‘Big.y’ for all instances of a given entry. I only want to fill some particular instances of that entry and leave other instances as empty.
B. For entry 10 and so on, the branch ‘Big.x’ and ‘Big.y’ are filled with some garbage values. I want these entries to be empty.

That is, I want something like this:

***********************************************************************
*    Row   * Instance * Wide.a    * Wide.b        * Big.x     * Big.y *
***********************************************************************
*        0 *        0 * 56.877945 * 56.137086 *         0 *         0 *
*        0 *        1 * 58.238992 *           *           *           *
*        0 *        2 * 150.36524 *           *           *           *
*        1 *        0 * 45.653616 * 69.914696 *         1 *         2 *
*        1 *        1 * 45.532576 *           *         1 *         2 *
*        2 *        0 * 49.053735 * 114.21307 *         2 *         4 *
*        3 *        0 *           * 44.001037 *         3 *         6 *
*        4 *        0 * 223.79526 *           *         4 *         8 *
*        5 *        0 * 103.84502 * 45.861062 *         5 *        10 *
*        6 *        0 * 56.055652 * 44.635575 *         6 *        12 *
*        6 *        1 * -10032.92 *           *           *           *
*        7 *        0 * 49.811174 *           *         7 *        14 *
*        8 *        0 * 45.785648 * 129.48804 *         8 *        16 *
*        9 *        0 * 46.765646 *           *         9 *        18 *
*       10 *        0 * 35.704076 * 21.099606 *           *           *
*       10 *        1 * 221.39279 *           *           *           *
*       11 *        0 * 40.141002 * 38.429454 *           *           *
*       11 *        1 * 29.690747 * 32.389832 *           *           *
*       12 *        0 *           * 30.231115 *           *           *
*       13 *        0 * 111.39832 * 299.24426 *           *           *
*       13 *        1 * 81.730985 * 117.39984 *           *           *

I hope I conveyed my idea.
Thanks.

Rather than

Which will fill all branches, you need to call:

    b->BackFill();

just for the new branch.

In you example, Wide appears to contain an array or collection of values. Scan will print one line per instance (or element) of that collection and for branches in the same Scan request that are not collection, it will repeat the single value in each instance lines.

I only want to fill some particular instances of that entry and leave other instances as empty.

To do so you will need to have a new branch contains/points-to a collection of the exact same size (for each entry) as the collection held in Wide.

B. For entry 10 and so on, the branch ‘Big.x’ and ‘Big.y’ are filled with some garbage values. I want these entries to be empty.

The code snippet explicitly put ‘nan’ there and Scan tries to print it (i.e. it does not have any special handling for nan).

I want these entries to be empty.

It turns out that the solution is the same as for the previous question. If Big was pointing to a collection (or variable size array) you could set that collection to be empy for any of the entries.

Thanks for the reply.

– I think doing the above you mentioned is a bit cumbersome since I would need to know the array size for each entry.
Never mind, I will skip this as of now.

–Let me make my problem a bit more simpler.

Let’s say I already have a branch ‘a’ in the TTree with 10 entries (row) as shown below. And now I would like to add a new branch ‘x’.
I want ‘x’ to be filled for some particular value of the entry (row) corresponding to the ‘a’. And for other entries, there should be no (empty) values filled. That is, say I want ‘x’ to have only 6 values as shown below.

root [1] OutputTree->Scan("a : x ")

**********************************************************
*    Row     * Instance   * a           * x  *
**********************************************************
*        0 *        0 * 56.877945  *           *   
*        1 *        0 * 45.653616  *           *        
*        2 *        0 * 49.053735  *         5 *        
*        3 *        0 *            *         9 *        
*        4 *        0 * 223.79526  *           *        
*        5 *        0 * 103.84502  *        12 *     
*        6 *        0 * 56.055652  *        14 *     
*        7 *        0 * 49.811174  *        17 *      
*        8 *        0 * 45.785648  *           *       
*        9 *        0 *            *           *     
*       10 *        0 * 35.704076  *        20 * 

Is there a way to achieve this?
Thanks.

I might be wrong but I don’t think there is currently a way to do that in ROOT. But in any case, why do you want that? If you want to store a ‘nan’, you are still storing something, so it won’t save space. Zeroes may not be good for your case, but you can always fill those “empty” entries with a number that you know will not occur in your data so that you can identify them, for example -99999 or whatever (any number outside the range of your data, or negative, or an exact integer, etc.). The values are compressed inside trees, so repeated numbers should not increase the file size significantly, if that’s a concern.

Thanks for the reply.

Because I just wanted to reduce the no. of entries for the new branch created.
–>With reference to my previous query:
Let’s say if the old ‘a’ branch had 10 entries, then by filling the “empty” entries of the new branch ‘x’ with some random no. -99999 will lead the new branch ‘x’ also having 10 entries. But infact it should only have 6.

I see. Thanks for the information.

I think doing the above you mentioned is a bit cumbersome since I would need to know the array size for each entry.

Yes and this information is easy to get (i.e. just read the original collection).

Is there a way to achieve this?

Yes.

I want ‘x’ to be filled for some particular value of the entry (row) corresponding to the ‘a’.

The straightforward way of doing this is having x to be a std::vector containing 0 or 1 elements depending of the entry.

Because I just wanted to reduce the no. of entries for the new branch created.

What is the main purpose?

Thanks for the reply.

The purpose is simply not to increase the no. of entries for that branch. As suggested above, I know, I can fill the empty entries with some known garbage no. (say, -99999) and then exclude those entries during my analysis. However, I wondered if there’s a way to fill some desired entries to be just ‘empty’.

Could you provide a snippet of code if possible?

Thanks.

The purpose is simply not to increase the no. of entries for that branch.

That was accomplished ‘per se’ already by the code that was calling only 'branch->BackFill. But I did not ask my question correctly. Ignoring the implementation details, why are you try to extend the TTree`, what is the semantic of the operation that you are trying to accomplish?

Could you provide a snippet of code if possible?

In this example, you will need to also generate the dictionary for Big and for std::vector<Big>.
You could also (without extra dictionary) store directly 2 std::vector<ULong64_t>

// This code was not compiled so may contain typos

// Defining a class                                                                                
 class Big  { 
     public: ULong64_t x;
             ULong64_t y;
}; 
                                                                                                                                                                                      
void treeAddBranch()
{                                                       
    TFile f("file.root", "update");
    auto t = f.Get<TTree>("OutputTree");            
    ULong64_t nentries = t->GetEntries();

    std::vector<Big> extra;
    TBranch *gb1 = t->Branch("Extra", &extra);                                                                                                                                                           
    
    //Fill some entries with some values
    for (ULong64_t i = 0; i < 10; i++)  
    {
        // Put some date in `extra` for example:
        extra.emplace_back({i*1, i*2});
        b->BackFill(); 
        extra.clear();
    }                                                                                                                                                  
    // Fill remaining entries as empty. 
    // `extra` is empty at this point
    for (ULong64_t i = 10; i < nentries; i++)
    { 
        b->BackFill();
    }
                                                                                                                                                                                                       
    t->Write("", TObject::kOverwrite); // save only the new version of the tree
    printf("A branch in 'file.root' file is added successfully.\n");
}