//C++ #include #include #include #include #include #include #include #include #include //root #include #include #include #include #include #include #include #include #include #include #include #include #include #include //BOOST #include #include #include #include template //template because we want to use r- and l-value std::strings std::vector parse_filenames(STR&& input_file_names, const std::string& workdir = "."){ std::vector input_files; //if the input string starts with '@', we have to parse a whole input file if(boost::algorithm::starts_with(input_file_names,"@")){ std::string line; std::ifstream myfile; myfile.open(input_file_names.substr(1).data());//substr returns the string without the '@' if(!myfile) myfile.open((workdir + "/" + input_file_names.substr(1)).data()); while(std::getline (myfile,line)) input_files.push_back(line);//TODO: could be that there is a trailing character that needs to be removed myfile.close(); } else //the input string doesn't start with '@', boost does the work for us :) boost::algorithm::split(input_files, input_file_names, boost::algorithm::is_any_of(";")); if(input_files.empty()) throw std::runtime_error("Is \"input_file_names\" empty?"); return input_files; } template //template because we want to use r- and l-value std::strings std::unique_ptr get_chain(STR1&& treename, STR2&& input_file_names, const std::string& workdir = ".", const std::string& chain_title = "Chain"){ auto input_files = parse_filenames(input_file_names,workdir); std::unique_ptr ch{new TChain(treename.data(),chain_title.data())}; for(auto& infn : input_files) ch->Add(infn.data()); if(!ch->GetFile()){ std::cout << "Cannot find input files. Trying to prepend workdir." << std::endl; for(auto& infn : input_files) ch->Add((workdir+"/"+infn).data()); if(!ch->GetFile()) throw std::runtime_error("TChain is empty. Check inputs!"); } return std::move(ch); } int tree_trimmerTDF(const std::string& ifn, const std::string& itn, const std::string& ofn , const std::string& cfn, const std::string& wd = "."){ TStopwatch clock; clock.Start(); //get input as TChain auto chain = get_chain(itn,ifn,wd); chain->SetCacheSize(); //get config-file boost::property_tree::ptree configtree; boost::property_tree::read_info(cfn,configtree,configtree); auto trim_vars = configtree.get_child_optional("variables"); auto tmp_msg = "Trimming input tree(s) with cut " + configtree.get("basiccuts",""); if(trim_vars) printf("%s and writing out %lu variables\n",tmp_msg.data(),configtree.get_child("variables").size()); else printf("%s and writing out full tree\n",tmp_msg.data()); std::vector branches_in = {}; std::vector default_branches_out = {}; std::vector> transformations; if(trim_vars) for(const auto& var : *trim_vars){ branches_in.push_back(var.first); if(var.first.find("[0]") != std::string::npos){ default_branches_out.push_back(boost::algorithm::replace_all_copy(var.first, "[0]", "Z")); transformations.emplace_back(default_branches_out.back(),var.first); } else if(auto nn = var.second.get_optional("new_name")){ default_branches_out.push_back(*nn); if(auto tfm = var.second.get_optional("transformation")) transformations.emplace_back(default_branches_out.back(),*tfm); else transformations.emplace_back(default_branches_out.back(),var.first); } else if(!var.second.get("to_output",1)) printf("Using %s only as input branch\n",var.first.data()); else default_branches_out.push_back(var.first); } //first, we need to know how many events there are and how many threads we use: ROOT::EnableImplicitMT(); ROOT::Experimental::TDataFrame d(*chain.get(),branches_in); std::vector::TInterfaceJittedDefine> df{d}; if(!transformations.empty()) for(const auto& tf : transformations){ printf("transforming %s to a new branch: %s\n",tf.second.data(),tf.first.data()); df.push_back(df.back().Define(tf.first,tf.second)); } //ROOT::Experimental::TDF::TSnapshotOptions tsno(configtree.get("outfopt","recreate")); //.Filter(configtree.get("basiccuts","")) df.back().Snapshot(configtree.get("outtreename",itn),wd + "/" + ofn,default_branches_out);//,tsno clock.Stop(); clock.Print(); return 0; }