3

# TChain

## class

A chain is a collection of files containg TTree objects. When the chain is created, the first parameter is the default name for the Tree to be processed later on.

Enter a new element in the chain via the TChain::Add function. Once a chain is defined, one can use the normal TTree functions to Draw,Scan,etc.

Use TChain::SetBranchStatus to activate one or more branches for all the trees in the chain.

public:
// TChain constants
enum {
kGlobalWeight   = BIT(15),
kAutoDelete     = BIT(16),
kProofUptodate  = BIT(17),
kProofLite      = BIT(18)
};

// This used to be 1234567890, if user code hardcoded this number, the user code will need to change.
static constexpr auto kBigNumber = TTree::kMaxEntries;

public:
TChain();
TChain(const char* name, const char* title = "");
virtual ~TChain();

virtual Int_t     Add(TChain* chain);
/// Add all files referenced by the passed chain to this chain.
/// The function returns the total number of files connected.

virtual Int_t     Add(const char* name, Long64_t nentries = TTree::kMaxEntries);
/// Add a new file to this chain.
/// If tree_name is missing the chain name will be assumed.
/// Wildcard treatment is triggered by the any of the special characters []*?
/// which may be used in the file name, eg. specifying "xxx*.root" adds
/// all files starting with xxx in the current file system directory.
/// where "query" is to be interpreted by the remote server. Wildcards may be
/// supported in urls, depending on the protocol plugin and the remote server.
/// http or https urls can contain a query identifier without tree_name, but
/// generally urls can not be written with them because of ambiguity with the
/// wildcard character. (Also see the documentaiton for TChain::AddFile,
/// which does not support wildcards but allows the url to contain query)
/// NB. To add all the files of a TChain to a chain, use Add(TChain *chain).
/// A. if nentries <= 0, the file is connected and the tree header read
///    in memory to get the number of entries.
/// B. if (nentries > 0, the file is not connected, nentries is assumed to be
///    the number of entries in the file. In this case, no check is made that
///    the file exists and the Tree existing in the file. This second mode
///    is interesting in case the number of entries in the file is already stored
///    in a run data base for example.
/// C. if (nentries == TTree::kMaxEntries) (default), the file is not connected.
///    the number of entries in each file will be read only when the file
///    will need to be connected to read an entry.
///    This option is the default and very efficient if one process
///    the chain sequentially. Note that in case TChain::GetEntry(entry)
///    is called and entry refers to an entry in the 3rd file, for example,
///    this forces the Tree headers in the first and second file
///    to be read to find the number of entries in these files.
///    Note that if one calls TChain::GetEntriesFast() after having created
///    a chain with this default, GetEntriesFast will return TTree::kMaxEntries!
///    TChain::GetEntries will force of the Tree headers in the chain to be
///    read to read the number of entries in each Tree.
/// D. The TChain data structure
///    Each TChainElement has a name equal to the tree name of this TChain
///    and a title equal to the file name.
/// Return value:
/// - If nentries>0 (including the default of TTree::kMaxEntries) and no
///   wildcarding is used, ALWAYS returns 1 without regard to whether
///   the file exists or contains the correct tree.
/// - If wildcarding is used, regardless of the value of nentries,
///   returns the number of files matching the name without regard to
///   whether they contain the correct tree.
/// - If nentries<=0 and wildcarding is not used, return 1 if the file
///  exists and contains the correct tree and 0 otherwise.

virtual Int_t     AddFile(const char* name, Long64_t nentries = TTree::kMaxEntries, const char* tname = "");
/// Add a new file to this chain.
/// Filename formats are similar to TChain::Add. Wildcards are not
/// applied. urls may also contain query and fragment identifiers
/// where the tree name can be specified in the url fragment.
/// If tree_name is given as a part of the file name it is used to
/// as the name of the tree to load from the file. Otherwise if tname
/// argument is specified the chain will load the tree named tname from
/// the file, otherwise the original treename specified in the TChain
/// constructor will be used.
/// A. If nentries <= 0, the file is opened and the tree header read
///    into memory to get the number of entries.
/// B. If nentries > 0, the file is not opened, and nentries is assumed
///    to be the number of entries in the file. In this case, no check
///    is made that the file exists nor that the tree exists in the file.
///    This second mode is interesting in case the number of entries in
///    the file is already stored in a run database for example.
/// C. If nentries == TTree::kMaxEntries (default), the file is not opened.
///    The number of entries in each file will be read only when the file
///    is opened to read an entry.  This option is the default and very
///    efficient if one processes the chain sequentially.  Note that in
///    case GetEntry(entry) is called and entry refers to an entry in the
///    third file, for example, this forces the tree headers in the first
///    and second file to be read to find the number of entries in those
///    files.  Note that if one calls GetEntriesFast() after having created
///    a chain with this default, GetEntriesFast() will return TTree::kMaxEntries!
///    Using the GetEntries() function instead will force all of the tree
///    headers in the chain to be read to read the number of entries in
///    each tree.
/// D. The TChain data structure
///    Each TChainElement has a name equal to the tree name of this TChain
///    and a title equal to the file name.
/// The function returns 1 if the file is successfully connected, 0 otherwise.

virtual Int_t     AddFileInfoList(TCollection* list, Long64_t nfiles = TTree::kMaxEntries);
/// Add all files referenced in the list to the chain. The object type in the
/// list must be either TFileInfo or TObjString or TUrl .
/// The function return 1 if successful, 0 otherwise.

virtual TFriendElement *AddFriend(const char* chainname, const char* dummy = "");
/// Add a TFriendElement to the list of friends of this chain.
/// A TChain has a list of friends similar to a tree (see TTree::AddFriend).
/// You can add a friend to a chain with the TChain::AddFriend method, and you
/// can retrieve the list of friends with TChain::GetListOfFriends.
/// The parameter is the name of friend chain (the name of a chain is always
/// the name of the tree from which it was created).
/// The original chain has access to all variable in its friends.
/// We can use the TChain::Draw method as if the values in the friends were
/// in the original chain.
/// If the variable name is enough to uniquely identify the variable, you can
/// leave out the chain and/or branch name.
/// When a TChain::Draw is executed, an automatic call to TTree::AddFriend
/// connects the trees in the chain. When a chain is deleted, its friend
/// elements are also deleted.
/// The number of entries in the friend must be equal or greater to the number
/// of entries of the original chain. If the friend has fewer entries a warning
/// is given and the resulting histogram will have missing entries.

virtual TFriendElement *AddFriend(const char* chainname, TFile* dummy);
/// Add the whole chain or tree as a friend of this chain.

virtual TFriendElement *AddFriend(TTree* chain, const char* alias = "", Bool_t warn = kFALSE);
/// Add the whole chain or tree as a friend of this chain.

virtual void      Browse(TBrowser*);/// Browse the contents of the chain.
virtual void      CanDeleteRefs(Bool_t flag = kTRUE);
/// When closing a file during the chain processing, the file
/// may be closed with option "R" if flag is set to kTRUE.
/// by default flag is kTRUE.
/// When closing a file with option "R", all TProcessIDs referenced by this
/// file are deleted.
/// Calling TFile::Close("R") might be necessary in case one reads a long list
/// of files having TRef, writing some of the referenced objects or TRef
/// to a new file. If the TRef or referenced objects of the file being closed
/// will not be referenced again, it is possible to minimize the size
/// of the TProcessID data structures in memory by forcing a delete of
/// the unused TProcessID.

virtual void      CreatePackets();/// Initialize the packet descriptor string.
virtual void      DirectoryAutoAdd(TDirectory *);/// Override the TTree::DirectoryAutoAdd behavior: we never auto add.
virtual Long64_t  Draw(const char* varexp, const TCut& selection, Option_t* option = "", Long64_t nentries = kMaxEntries, Long64_t firstentry = 0);
/// Draw expression varexp for selected entries.
/// Returns -1 in case of error or number of selected events in case of success.
/// This function accepts TCut objects as arguments.
/// Useful to use the string operator +, example:
///    ntuple.Draw("x",cut1+cut2+cut3);

virtual Long64_t  Draw(const char* varexp, const char* selection, Option_t* option = "", Long64_t nentries = kMaxEntries, Long64_t firstentry = 0); // *MENU*
/// Process all entries in this chain and draw histogram corresponding to
/// expression varexp.
/// Returns -1 in case of error or number of selected events in case of success.

virtual void      Draw(Option_t* opt) { Draw(opt, "", "", kMaxEntries, 0); }
virtual Int_t     Fill() { MayNotUse("Fill()"); return -1; }
virtual TBranch  *FindBranch(const char* name);/// See TTree::GetReadEntry().
virtual TLeaf    *FindLeaf(const char* name);/// See TTree::GetReadEntry().
virtual TBranch  *GetBranch(const char* name);/// Return pointer to the branch name in the current tree.
virtual Bool_t    GetBranchStatus(const char* branchname) const;/// See TTree::GetReadEntry().
virtual Long64_t  GetCacheSize() const { return fTree ? fTree->GetCacheSize() : fCacheSize; }
virtual Long64_t  GetChainEntryNumber(Long64_t entry) const;
/// Return absolute entry number in the chain.
/// The input parameter entry is the entry number in
/// the current tree of this chain.

virtual TClusterIterator GetClusterIterator(Long64_t firstentry);
/// Return an iterator over the cluster of baskets starting at firstentry.
/// This iterator is not yet supported for TChain object.

Int_t     GetNtrees() const { return fNtrees; }
virtual Long64_t  GetEntries() const;
/// Return the total number of entries in the chain.
/// In case the number of entries in each tree is not yet known,
/// the offset table is computed.

virtual Long64_t  GetEntries(const char *sel) { return TTree::GetEntries(sel); }
virtual Int_t     GetEntry(Long64_t entry=0, Int_t getall=0);
/// Get entry from the file to memory.
/// - getall = 0 : get only active branches
/// - getall = 1 : get all branches
/// Return the total number of bytes read,
/// 0 bytes read indicates a failure.

virtual Long64_t  GetEntryNumber(Long64_t entry) const;
/// Return entry number corresponding to entry.
/// if no TEntryList set returns entry
/// else returns entry #entry from this entry list and
/// also computes the global entry number (loads all tree headers)

virtual Int_t     GetEntryWithIndex(Int_t major, Int_t minor=0);
/// Return entry corresponding to major and minor number.
/// The function returns the total number of bytes read.
/// If the Tree has friend trees, the corresponding entry with
/// the index values (major,minor) is read. Note that the master Tree
/// and its friend may have different entry serial numbers corresponding
/// to (major,minor).

TFile            *GetFile() const;
/// Return a pointer to the current file.
/// If no file is connected, the first file is automatically loaded.

virtual TLeaf    *GetLeaf(const char* branchname, const char* leafname);/// Return a pointer to the leaf name in the current tree.
virtual TLeaf    *GetLeaf(const char* name);
/// Return a pointer to the leaf name in the current tree.

virtual TObjArray *GetListOfBranches();
//                Warning, GetListOfFiles returns the list of TChainElements (not the list of files)
/// Return a pointer to the list of branches of the current tree.
/// Warning: If there is no current TTree yet, this routine will open the
/// first in the chain.
/// Returns 0 on failure.

//                see TChain::AddFile to see how to get the corresponding TFile objects
TObjArray        *GetListOfFiles() const {return fFiles;}
virtual TObjArray *GetListOfLeaves();
virtual const char *GetAlias(const char *aliasName) const;/// Returns the expanded value of the alias.  Search in the friends if any.
virtual Double_t  GetMaximum(const char *columname);/// Return maximum of column with name columname.
virtual Double_t  GetMinimum(const char *columname);/// Return minimum of column with name columname.
virtual Int_t     GetNbranches();/// Return the number of branches of the current tree. Warning: May set the current tree!
TList            *GetStatus() const { return fStatus; }
virtual TTree    *GetTree() const { return fTree; }
virtual Int_t     GetTreeNumber() const { return fTreeNumber; }
Long64_t *GetTreeOffset() const { return fTreeOffset; }
Int_t     GetTreeOffsetLen() const { return fTreeOffsetLen; }
virtual Double_t  GetWeight() const;
/// Return the chain weight.
/// By default the weight is the weight of the current tree.
/// However, if the weight has been set in TChain::SetWeight()
/// with the option "global", then that weight will be returned.
/// Warning: May set the current tree!

/// Dummy function.
/// It could be implemented and load all baskets of all trees in the chain.
/// For the time being use TChain::Merge and TTree::LoadBasket
/// on the resulting tree.

virtual Long64_t  LoadTree(Long64_t entry);
/// Find the tree which contains entry, and set it as the current tree.
/// Returns the entry number in that tree.
/// The input argument entry is the entry serial number in the whole chain.
/// In case of error, LoadTree returns a negative number:
///   1. The chain is empty.
///   2. The requested entry number of less than zero or too large for the chain.
///       or too large for the large TTree.
///   3. The file corresponding to the entry could not be correctly open
///   4. The TChainElement corresponding to the entry is missing or
///       the TTree is missing from the file.
/// Note: This is the only routine which sets the value of fTree to
///       a non-zero pointer.

void      Lookup(Bool_t force = kFALSE);
/// Check / locate the files in the chain.
/// By default only the files not yet looked up are checked.
/// Use force = kTRUE to check / re-check every file.

virtual void      Loop(Option_t *option="", Long64_t nentries=kMaxEntries, Long64_t firstentry=0); // *MENU* /// Loop on nentries of this chain starting at firstentry.  (NOT IMPLEMENTED)
virtual void      ls(Option_t *option="") const;/// List the chain.
virtual Long64_t  Merge(const char *name, Option_t *option = "");
/// Merge all the entries in the chain into a new tree in a new file.
/// See important note in the following function Merge().
/// If the chain is expecting the input tree inside a directory,
/// this directory is NOT created by this routine.

virtual Long64_t  Merge(TCollection *list, Option_t *option = "");/// Merge all chains in the collection.  (NOT IMPLEMENTED)
virtual Long64_t  Merge(TCollection *list, TFileMergeInfo *info);/// Merge all chains in the collection.  (NOT IMPLEMENTED)
virtual Long64_t  Merge(TFile *file, Int_t basketsize, Option_t *option="");
/// Merge all the entries in the chain into a new tree in the current file.
/// Note: The "file" parameter is *not* the file where the new
///       tree will be inserted.  The new tree is inserted into
///       gDirectory, which is usually the most recently opened
///       file, or the directory most recently cd()'d to.
/// If option = "C" is given, the compression level for all branches
/// in the new Tree is set to the file compression level.  By default,
/// the compression level of all branches is the original compression
/// level in the old trees.
/// If basketsize > 1000, the basket size for all branches of the
/// new tree will be set to basketsize.
/// If 'option' contains the word 'fast' the merge will be done without
/// unzipping or unstreaming the baskets (i.e., a direct copy of the raw
/// bytes on disk).
/// When 'fast' is specified, 'option' can also contains a
/// sorting order for the baskets in the output file.
/// There is currently 3 supported sorting order:
///     SortBasketsByOffset (the default)
/// When using SortBasketsByOffset the baskets are written in
/// the output file in the same order as in the original file
/// (i.e. the basket are sorted on their offset in the original
/// file; Usually this also means that the baskets are sorted
/// on the index/number of the _last_ entry they contain)
/// When using SortBasketsByBranch all the baskets of each
/// individual branches are stored contiguously.  This tends to
/// optimize reading speed when reading a small number (1->5) of
/// branches, since all their baskets will be clustered together
/// instead of being spread across the file.  However it might
/// decrease the performance when reading more branches (or the full
/// entry).
/// When using SortBasketsByEntry the baskets with the lowest
/// starting entry are written first.  (i.e. the baskets are
/// sorted on the index/number of the first entry they contain).
/// This means that on the file the baskets will be in the order
/// in which they will be needed when reading the whole tree
/// sequentially.
/// ## IMPORTANT Note 1: AUTOMATIC FILE OVERFLOW
/// When merging many files, it may happen that the resulting file
/// reaches a size > TTree::fgMaxTreeSize (default = 1.9 GBytes).
/// In this case the current file is automatically closed and a new
/// file started.  If the name of the merged file was "merged.root",
/// the subsequent files will be named "merged_1.root", "merged_2.root",
/// etc.  fgMaxTreeSize may be modified via the static function
/// TTree::SetMaxTreeSize.
/// When in fast mode, the check and switch is only done in between each
/// input file.
/// ## IMPORTANT Note 2: The output file is automatically closed and deleted.
/// This is required because in general the automatic file overflow described
/// above may happen during the merge.
/// If only the current file is produced (the file passed as first argument),
/// one can instruct Merge to not close and delete the file by specifying
/// the option "keep".

virtual void      Print(Option_t *option="") const;
/// Print the header information of each tree in the chain.
/// See TTree::Print for a list of options.

virtual Long64_t  Process(const char *filename, Option_t *option="", Long64_t nentries=kMaxEntries, Long64_t firstentry=0); // *MENU*
/// Process all entries in this chain, calling functions in filename.
/// The return value is -1 in case of error and TSelector::GetStatus() in
/// in case of success.
/// See TTree::Process.

virtual Long64_t  Process(TSelector* selector, Option_t* option = "", Long64_t nentries = kMaxEntries, Long64_t firstentry = 0);
/// Process this chain executing the code in selector.
/// The return value is -1 in case of error and TSelector::GetStatus() in
/// in case of success.

virtual void      RecursiveRemove(TObject *obj);/// Make sure that obj (which is being deleted or will soon be) is no longer referenced by this TTree.
virtual void      RemoveFriend(TTree*);/// Remove a friend from the list of friends.
virtual void      Reset(Option_t *option="");/// Resets the state of this chain.
virtual void      ResetAfterMerge(TFileMergeInfo *);/// Resets the state of this chain after a merge (keep the customization but forget the data).
virtual void      ResetBranchAddress(TBranch *);/// Reset the addresses of the branch.
virtual void      ResetBranchAddresses();/// Reset the addresses of the branches.
virtual Long64_t  Scan(const char *varexp="", const char *selection="", Option_t *option="", Long64_t nentries=kMaxEntries, Long64_t firstentry=0); // *MENU*
/// Loop on tree and print entries passing selection.
/// - If varexp is 0 (or "") then print only first 8 columns.
/// - If varexp = "*" print all columns.
/// - Otherwise a columns selection can be made using "var1:var2:var3".

virtual void      SetAutoDelete(Bool_t autodel=kTRUE);
/// Set the global branch kAutoDelete bit.
/// When LoadTree loads a new Tree, the branches for which
/// the address is set will have the option AutoDelete set
/// For more details on AutoDelete, see TBranch::SetAutoDelete.

virtual Int_t     SetBranchAddress(const char *bname,void *add, TBranch **ptr = 0);
/// Set branch address.
/// \param[in] bname    is the name of a branch.
/// \param[in] add      is the address of the branch.
/// Note: See the comments in TBranchElement::SetAddress() for a more
/// detailed discussion of the meaning of the add parameter.
/// IMPORTANT REMARK:
/// In case TChain::SetBranchStatus is called, it must be called
/// BEFORE calling this function.
/// See TTree::CheckBranchAddressType for the semantic of the return value.

virtual Int_t     SetBranchAddress(const char *bname,void *add, TBranch **ptr, TClass *realClass, EDataType datatype, Bool_t isptr);
/// Check if bname is already in the status list, and if not, create a TChainElement object and set its address.
/// See TTree::CheckBranchAddressType for the semantic of the return value.
/// Note: See the comments in TBranchElement::SetAddress() for a more
/// detailed discussion of the meaning of the add parameter.

virtual Int_t     SetBranchAddress(const char *bname,void *add, TClass *realClass, EDataType datatype, Bool_t isptr);
/// Check if bname is already in the status list, and if not, create a TChainElement object and set its address.
/// See TTree::CheckBranchAddressType for the semantic of the return value.
/// Note: See the comments in TBranchElement::SetAddress() for a more
/// detailed discussion of the meaning of the add parameter.

template <class T> Int_t SetBranchAddress(const char *bname, T **add, TBranch **ptr = 0) {
}
#ifndef R__NO_CLASS_TEMPLATE_SPECIALIZATION
// This can only be used when the template overload resolution can distringuish between
// T* and T**
template <class T> Int_t SetBranchAddress(const char *bname, T *add, TBranch **ptr = 0) {
}
#endif

virtual void      SetBranchStatus(const char *bname, Bool_t status=1, UInt_t *found=0);
/// Set branch status to Process or DoNotProcess
/// \param[in] bname     is the name of a branch. if bname="*", apply to all branches.
/// \param[in] status    = 1  branch will be processed,
///                      = 0  branch will not be processed
///  See IMPORTANT REMARKS in TTree::SetBranchStatus and TChain::SetBranchAddress
///  If found is not 0, the number of branch(es) found matching the regular
///  expression is returned in *found AND the error message 'unknown branch'
///  is suppressed.

virtual Int_t     SetCacheSize(Long64_t cacheSize = -1);
virtual void      SetDirectory(TDirectory *dir);
/// Remove reference to this chain from current directory and add
/// reference to new directory dir. dir can be 0 in which case the chain
/// does not belong to any directory.

virtual void      SetEntryList(TEntryList *elist, Option_t *opt="");
/// Set the input entry list (processing the entries of the chain will then be
/// limited to the entries in the list)
/// This function finds correspondance between the sub-lists of the TEntryList
/// and the trees of the TChain
/// By default (opt=""), both the file names of the chain elements and
/// the file names of the TEntryList sublists are expanded to full path name.
/// If opt = "ne", the file names are taken as they are and not expanded

virtual void      SetEntryListFile(const char *filename="", Option_t *opt="");
/// Set the input entry list (processing the entries of the chain will then be
/// limited to the entries in the list). This function creates a special kind
/// of entry list (TEntryListFromFile object) that loads lists, corresponding
/// to the chain elements, one by one, so that only one list is in memory at a time.
/// If there is an error opening one of the files, this file is skipped and the next file is loaded
/// File naming convention:
/// - by default, filename_elist.root is used, where filename is the
///   name of the chain element
/// - xxx$xxx.root -$ sign is replaced by the name of the chain element
/// If the list name is not specified (by passing filename_elist.root/listname to
/// the TChain::SetEntryList() function, the first object of class TEntryList
/// in the file is taken.
/// It is assumed, that there are as many list files, as there are elements in
/// the chain and they are in the same order

virtual void      SetEventList(TEventList *evlist);
/// This function transfroms the given TEventList into a TEntryList
/// NOTE, that this function loads all tree headers, because the entry numbers
/// in the TEventList are global and have to be recomputed, taking into account
/// the number of entries in each tree.
/// The new TEntryList is owned by the TChain and gets deleted when the chain
/// is deleted. This TEntryList is returned by GetEntryList() function, and after
/// GetEntryList() function is called, the TEntryList is not owned by the chain
/// any more and will not be deleted with it.

virtual void      SetMakeClass(Int_t make) { TTree::SetMakeClass(make); if (fTree) fTree->SetMakeClass(make);}
virtual void      SetPacketSize(Int_t size = 100);/// Set number of entries per packet for parallel root.
virtual void      SetProof(Bool_t on = kTRUE, Bool_t refresh = kFALSE, Bool_t gettreeheader = kFALSE);
/// Enable/Disable PROOF processing on the current default Proof (gProof).
/// "Draw" and "Processed" commands will be handled by PROOF.
/// The refresh and gettreeheader are meaningfull only if on == kTRUE.
/// If refresh is kTRUE the underlying fProofChain (chain proxy) is always
/// rebuilt (even if already existing).
/// If gettreeheader is kTRUE the header of the tree will be read from the
/// PROOF cluster: this is only needed for browsing and should be used with
/// care because it may take a long time to execute.

virtual void      SetWeight(Double_t w=1, Option_t *option="");
/// Set chain weight.
/// The weight is used by TTree::Draw to automatically weight each
/// selected entry in the resulting histogram.
/// For example the equivalent of
/// ~~~ {.cpp}
///     chain.Draw("x","w")
/// ~~~
/// is
/// ~~~ {.cpp}
///     chain.SetWeight(w,"global");
///     chain.Draw("x");
/// ~~~
/// By default the weight used will be the weight
/// of each Tree in the TChain. However, one can force the individual
/// weights to be ignored by specifying the option "global".
/// In this case, the TChain global weight will be used for all Trees.

virtual void      UseCache(Int_t maxCacheSize = 10, Int_t pageSize = 0);


## code

///  Suppose we have 3 files f1.root, f2.root and f3.root. Each file contains a TTree object named "T".
TChain ch("T");  creates a chain to process a Tree called "T"
ch.Draw("x");

/// Each TChainElement has a name equal to the tree name of this TChain and a title equal to the file name. So, to loop over the TFiles that have been added to this chain:

TObjArray *fileElements=chain->GetListOfFiles();
TIter next(fileElements);
TChainElement *chEl=0;
while (( chEl=(TChainElement*)next() )) {
TFile f(chEl->GetTitle());
//   ... do something with f ...
}

/// Example using the file generated in \$ROOTSYS/test/Event
/// merge two copies of Event.root

TChain ch("T");
ch.Merge("all.root");

/// If the chain is expecting the input tree inside a directory,
/// this directory is NOT created by this routine.
///
/// So if you do:

TChain ch("mydir/mytree");
ch.Merge("newfile.root");

/// The resulting file will not have subdirectories.  In order to
/// preserve the directory structure do the following instead:

TFile* file = TFile::Open("newfile.root", "RECREATE");
file->mkdir("mydir")->cd();
ch.Merge(file);

/// The function returns the total number of files produced.
/// To check that all files have been merged use something like:

if (newchain->GetEntries()!=oldchain->GetEntries()) {
... not all the file have been copied ...
}

/// This example has four chains each has 20 ROOT trees from 20 ROOT files.

TChain ch("t"); // a chain with 20 trees from 20 files
TChain ch1("t1");
TChain ch2("t2");
TChain ch3("t3");

/// Now we can add the friends to the first chain.

/// For example, this generates a 3-d scatter plot of variable "var" in the
/// TChain ch versus variable v1 in TChain t1 versus variable v2 in TChain t2.

ch.Draw("var:t1.v1:t2.v2");


## example

updated: 2018-05-14 17:18:22