// Copyright (C) 2010, Guy Barrand. All rights reserved. // See the file tools.license for terms. #ifndef tools_wroot_ntuple #define tools_wroot_ntuple // An ntuple class to write at the CERN-ROOT format. // It inherits wroot::tree and each column is mapped // on a (wroot::branch,wroot::leaf). Each add_row() does a tree::fill(). #include "tree" #include "icol" #include "../vfind" #include "../vmanip" #include "../ntuple_booking" #include "../sout" #include "../scast" #include "../forit" #ifdef TOOLS_MEM #include "../mem" #endif namespace tools { namespace wroot { class ntuple : public tree { public: //typedef tools::wroot::icol icol; //for backward compatibility. public: template class column : public virtual icol { #ifdef TOOLS_MEM static const std::string& s_class() { static const std::string s_v("tools::wroot::ntuple::column<"+stype(T())+">"); return s_v; } #endif public: static cid id_class() { static const T s_v = T(); //do that for T = std::string. return _cid(s_v); } virtual void* cast(cid a_class) const { if(void* p = cmp_cast(this,a_class)) {return p;} else return 0; } virtual cid id_cls() const {return id_class();} public: //icol virtual void add() {m_leaf->fill(m_tmp);} virtual void set_def() {m_tmp = m_def;} virtual const std::string& name() const {return m_leaf->name();} virtual void set_basket_size(uint32 a_size) {m_branch->set_basket_size(a_size);} virtual branch* get_branch() const {return m_branch;} virtual base_leaf* get_leaf() const {return m_leaf;} public: column(tree& a_tree,const std::string& a_name,const T& a_def) :m_tree(a_tree),m_branch(0),m_leaf(0) ,m_def(a_def),m_tmp(a_def) { #ifdef TOOLS_MEM mem::increment(s_class().c_str()); #endif m_branch = m_tree.create_branch(a_name); m_leaf = m_branch->create_leaf(a_name,a_name); } virtual ~column(){ #ifdef TOOLS_MEM mem::decrement(s_class().c_str()); #endif } protected: column(const column& a_from) :icol(a_from) ,m_tree(a_from.m_tree) ,m_branch(0) ,m_leaf(0) ,m_def(a_from.m_def) ,m_tmp(a_from.m_tmp) {} column& operator=(const column& a_from){ if(&a_from==this) return *this; m_branch = 0; m_leaf = 0; m_def = a_from.m_def; m_tmp = a_from.m_tmp; return *this; } public: bool fill(const T& a_value) {m_tmp = a_value;return true;} protected: tree& m_tree; branch* m_branch; leaf* m_leaf; T m_def; T m_tmp; }; class column_string : public virtual icol { #ifdef TOOLS_MEM static const std::string& s_class() { static const std::string s_v("tools::wroot::ntuple::column_string"); return s_v; } #endif public: static cid id_class() { static const std::string s_v; return _cid(s_v); } virtual void* cast(cid a_class) const { if(void* p = cmp_cast(this,a_class)) {return p;} else return 0; } virtual cid id_cls() const {return id_class();} public: //icol virtual void add() {m_leaf->fill(m_tmp);} virtual void set_def() {m_tmp = m_def;} virtual const std::string& name() const {return m_leaf->name();} virtual void set_basket_size(uint32 a_size) {m_branch->set_basket_size(a_size);} virtual branch* get_branch() const {return m_branch;} virtual base_leaf* get_leaf() const {return m_leaf;} public: column_string(tree& a_tree,const std::string& a_name,const std::string& a_def) :m_tree(a_tree),m_branch(0),m_leaf(0) ,m_def(a_def),m_tmp(a_def) { #ifdef TOOLS_MEM mem::increment(s_class().c_str()); #endif m_branch = m_tree.create_branch(a_name); m_leaf = m_branch->create_leaf_string(a_name,a_name); } virtual ~column_string(){ #ifdef TOOLS_MEM mem::decrement(s_class().c_str()); #endif } protected: column_string(const column_string& a_from) :icol(a_from) ,m_tree(a_from.m_tree) ,m_branch(0) ,m_leaf(0) ,m_def(a_from.m_def) ,m_tmp(a_from.m_tmp) {} column_string& operator=(const column_string& a_from){ if(&a_from==this) return *this; m_branch = 0; m_leaf = 0; m_def = a_from.m_def; m_tmp = a_from.m_tmp; return *this; } public: bool fill(const std::string& a_value) {m_tmp = a_value;return true;} protected: tree& m_tree; branch* m_branch; leaf_string* m_leaf; std::string m_def; std::string m_tmp; }; template class std_vector_column : public virtual icol { #ifdef TOOLS_MEM static const std::string& s_class() { static const std::string s_v("tools::wroot::ntuple::std_vector_column<"+stype(T())+">"); return s_v; } #endif public: static cid id_class() {return _cid_std_vector();} virtual void* cast(cid a_class) const { if(void* p = cmp_cast(this,a_class)) {return p;} else return 0; } virtual cid id_cls() const {return id_class();} public: //icol virtual void add() {} virtual void set_def() {} virtual const std::string& name() const {return m_leaf->name();} virtual void set_basket_size(uint32 a_size) {m_branch->set_basket_size(a_size);} virtual branch* get_branch() const {return m_branch;} virtual base_leaf* get_leaf() const {return m_leaf;} public: std_vector_column(tree& a_tree,const std::string& a_name,std::vector& a_user_vec) :m_tree(a_tree) ,m_user_vec(a_user_vec) ,m_branch(0) ,m_leaf(0) { #ifdef TOOLS_MEM mem::increment(s_class().c_str()); #endif std_vector_be* br = m_tree.create_std_vector_be(a_name,m_user_vec); m_leaf = br->create_leaf_element(a_name,a_name); m_branch = br; } virtual ~std_vector_column(){ #ifdef TOOLS_MEM mem::decrement(s_class().c_str()); #endif } protected: std_vector_column(const std_vector_column& a_from) :icol(a_from) ,m_tree(a_from.m_tree) ,m_user_vec(a_from.m_user_vec) ,m_branch(0) ,m_leaf(0) {} std_vector_column& operator=(const std_vector_column& a_from){ if(&a_from==this) return *this; m_branch = 0; m_leaf = 0; return *this; } protected: tree& m_tree; std::vector& m_user_vec; branch* m_branch; leaf_element* m_leaf; }; public: ntuple(idir& a_dir,const std::string& a_name,const std::string& a_title):tree(a_dir,a_name,a_title){} ntuple(idir& a_dir,const ntuple_booking& a_bkg):tree(a_dir,a_bkg.name(),a_bkg.title()) { const std::vector& cols = a_bkg.columns(); tools_vforcit(column_booking,cols,it){ if((*it).cls_id()==_cid(char(0))) { create_column((*it).name()); } else if((*it).cls_id()==_cid(short(0))) { create_column((*it).name()); } else if((*it).cls_id()==_cid(int(0))) { create_column((*it).name()); } else if((*it).cls_id()==_cid(float(0))) { create_column((*it).name()); } else if((*it).cls_id()==_cid(double(0))) { create_column((*it).name()); } else if((*it).cls_id()==_cid(std::string())) { create_column_string((*it).name()); } else if((*it).cls_id()==_cid_std_vector()) { std::vector* vec = (std::vector*)(*it).user_obj(); if(vec) { create_column((*it).name(),*vec); } else { m_out << "tools::wroot::ntuple :" << " for std::vector column " << sout((*it).name()) << ", the user vector pointer is null." << std::endl; tools::clear(m_cols); tools::clear(m_branches); return; } } else if((*it).cls_id()==_cid_std_vector()) { std::vector* vec = (std::vector*)(*it).user_obj(); if(vec) { create_column((*it).name(),*vec); } else { m_out << "tools::wroot::ntuple :" << " for std::vector column " << sout((*it).name()) << ", the user vector pointer is null." << std::endl; tools::clear(m_cols); tools::clear(m_branches); return; } } else if((*it).cls_id()==_cid_std_vector()) { std::vector* vec = (std::vector*)(*it).user_obj(); if(vec) { create_column((*it).name(),*vec); } else { m_out << "tools::wroot::ntuple :" << " for std::vector column " << sout((*it).name()) << ", the user vector pointer is null." << std::endl; tools::clear(m_cols); tools::clear(m_branches); return; } } else if((*it).cls_id()==_cid_std_vector()) { std::vector* vec = (std::vector*)(*it).user_obj(); if(vec) { create_column((*it).name(),*vec); } else { m_out << "tools::wroot::ntuple :" << " for std::vector column " << sout((*it).name()) << ", the user vector pointer is null." << std::endl; tools::clear(m_cols); tools::clear(m_branches); return; } } else if((*it).cls_id()==_cid_std_vector()) { std::vector* vec = (std::vector*)(*it).user_obj(); if(vec) { create_column((*it).name(),*vec); } else { m_out << "tools::wroot::ntuple :" << " for std::vector column " << sout((*it).name()) << ", the user vector pointer is null." << std::endl; tools::clear(m_cols); tools::clear(m_branches); return; } // no leaf_store_class() defined for the other types. } else { m_out << "tools::wroot::ntuple :" << " for column " << sout((*it).name()) << ", type with cid " << (*it).cls_id() << " not yet handled." << std::endl; //throw tools::clear(m_cols); tools::clear(m_branches); return; } } } virtual ~ntuple() { tools::clear(m_cols); } protected: ntuple(const ntuple& a_from):iobject(a_from),itree(a_from),tree(a_from){} ntuple& operator=(const ntuple&){return *this;} public: const std::vector& columns() const {return m_cols;} std::vector& columns() {return m_cols;} template column* create_column(const std::string& a_name,const T& a_def = T()) { if(find_named(m_cols,a_name)) return 0; column* col = new column(*this,a_name,a_def); if(!col) return 0; m_cols.push_back(col); return col; } column_string* create_column_string(const std::string& a_name,const std::string& a_def = std::string()) { if(find_named(m_cols,a_name)) return 0; column_string* col = new column_string(*this,a_name,a_def); if(!col) return 0; m_cols.push_back(col); return col; } template std_vector_column* create_column(const std::string& a_name,std::vector& a_user_vec) { //NOTE : to optimize, we do not handle a default std::vector value logic. if(find_named(m_cols,a_name)) return 0; std_vector_column* col = new std_vector_column(*this,a_name,a_user_vec); if(!col) return 0; m_cols.push_back(col); return col; } template column* find_column(const std::string& a_name) { icol* col = find_named(m_cols,a_name); if(!col) return 0; return id_cast >(*col); } column_string* find_column_string(const std::string& a_name) { icol* col = find_named(m_cols,a_name); if(!col) return 0; return id_cast(*col); } bool add_row() { if(m_cols.empty()) return false; tools_vforit(icol*,m_cols,it) (*it)->add(); uint32 n; bool status = tree::fill(n); tools_vforit(icol*,m_cols,it) (*it)->set_def(); return status; } void set_basket_size(uint32 a_size) {tools_vforit(icol*,m_cols,it) (*it)->set_basket_size(a_size);} /////////////////////////////////////////////////////////////////////////// /// for parallelization : ///////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// void get_branches(std::vector& a_vec) const { a_vec.clear(); tools_vforcit(icol*,m_cols,it) a_vec.push_back((*it)->get_branch()); } bool merge_number_of_entries() { m_entries = 0; //it should be zero! m_tot_bytes = 0; m_zip_bytes = 0; bool status = true; tools_vforit(icol*,m_cols,it) { if(it==m_cols.begin()) { m_entries = (*it)->get_branch()->entries(); } else if(m_entries!=(*it)->get_branch()->entries()) { m_out << "tools::wroot::ntuple::merge_number_of_entries :" << " branches do not have same number of entries." << std::endl; status = false; } m_tot_bytes += (*it)->get_branch()->tot_bytes(); m_zip_bytes += (*it)->get_branch()->zip_bytes(); } return status; } protected: std::vector m_cols; }; }} #endif