CombineHarvester
CardWriter.cc
Go to the documentation of this file.
2 #include <iostream>
3 #include <set>
4 #include <string>
5 #include <vector>
6 #include "boost/format.hpp"
9 
10 namespace ch {
11 
12 CardWriter::CardWriter(std::string const& text_pattern,
13  std::string const& root_pattern)
14  : text_pattern_(text_pattern),
15  root_pattern_(root_pattern),
16  wildcard_masses_({"*"}),
17  v_(0),
18  create_dirs_(true) {}
19 
21  v_ = v;
22  return *this;
23 }
24 
26  create_dirs_ = flag;
27  return *this;
28 }
29 
30 
32  std::vector<std::string> const& masses) {
33  wildcard_masses_ = masses;
34  return *this;
35 }
36 
37 auto CardWriter::BuildMap(std::string const& pattern,
38  ch::CombineHarvester& cmb) const -> PatternMap {
39  PatternMap f_map;
40  // We first filter Objects having a mass value in the wildcard list
41  cmb.cp().mass(wildcard_masses_, false)
42  .ForEachObj([&](ch::Object const* obj) {
43  // Build the fully-compiled key
44  std::string key = Compile(pattern, obj);
45  if (f_map.count(key)) return;
46  std::set<std::string> mappings;
47  // The fully-compiled pattern always goes in
48  mappings.insert(key);
49  // Compile again, but this time skipping the $MASS substitution
50  std::string maps_pattern = Compile(pattern, obj, true);
51  // Create a set of patterns by substituting each mass wildcard
52  for (auto m : wildcard_masses_) {
53  std::string tmp = maps_pattern;
54  boost::replace_all(tmp, "$MASS", m);
55  mappings.insert(tmp);
56  }
57  f_map[key] = mappings;
58  });
59  auto masses = cmb.cp().mass(wildcard_masses_, false).mass_set();
60  cmb.cp().mass(wildcard_masses_, true)
61  .ForEachObj([&](ch::Object const* obj) {
62  // Build the fully-compiled key
63  std::string key = Compile(pattern, obj, true);
64  for (auto m : masses) {
65  std::string full_key = key;
66  boost::replace_all(full_key, "$MASS", m);
67  if (f_map.count(full_key)) continue;
68  std::set<std::string> mappings;
69  // The fully-compiled pattern always goes in
70  std::string wildcard_key = key;
71  boost::replace_all(wildcard_key, "$MASS", obj->mass());
72  mappings.insert(wildcard_key);
73  f_map[full_key] = mappings;
74  }
75  });
76  /*for (auto const& it : f_map) {
77  std::cout << it.first << ": ";
78  for (auto const& it2 : it.second) std::cout << it2 << " ";
79  std::cout << "\n";
80  }*/
81  return f_map;
82 }
83 
84 void CardWriter::MakeDirs(PatternMap const& map) const {
85  std::set<boost::filesystem::path> mk_dirs;
86  for (auto const& f : map) {
87  mk_dirs.insert(boost::filesystem::path(f.first).parent_path());
88  }
89  for (auto & dir : mk_dirs) {
90  FNLOGC(std::cout, v_ > 0) << "Creating dir " << dir.string() << "\n";
91 
92  boost::filesystem::create_directories(dir);
93  }
94 }
95 
96 std::map<std::string, CombineHarvester> CardWriter::WriteCards(std::string const& tag,
97  ch::CombineHarvester& cmb) const {
98  #ifdef TIME_FUNCTIONS
99  LAUNCH_FUNCTION_TIMER(__timer__, __token__)
100  #endif
101 
102  // Update the current "$TAG" value
103  tag_ = tag;
104 
105  // Build the set of files we need to create (the map keys), and associate a
106  // set of compiled Object patterns that are associated to each file (the map
107  // values). One entry will typically look like:
108  //
109  // ["htt_mt_125.root"] = {"htt_mt_125.root", "htt_mt_*.root"}
110  //
111  // i.e. in addition to getting a pattern identical to the filename, we also
112  // get a pattern where each $MASS placeholder has been replaced by a wildcard
113  // expression.
114  auto f_map = BuildMap(root_pattern_, cmb);
115 
116  if (create_dirs_) MakeDirs(f_map);
117 
118  // It turns out that the Compile method takes a small but appreciable amount
119  // of CPU time. To evaluate it every time it's needed could be O(10^7) calls,
120  // equivalent to tens of seconds for a complex model. To avoid this we just
121  // calculate once for each ch::Object and store the result in a map, which we
122  // use as a look-up later.
123  std::map<Object const*, std::string> root_map;
124  cmb.ForEachObj([&](ch::Object const* obj) {
125  root_map[obj] = Compile(root_pattern_, obj);
126  });
127  std::map<Object const*, std::string> text_map;
128  cmb.ForEachObj([&](ch::Object const* obj) {
129  text_map[obj] = Compile(text_pattern_, obj);
130  });
131 
132  std::map<std::string, CombineHarvester> datacards;
133  for (auto const& f : f_map) {
134  // Create each ROOT file (overwrite pre-existing)
135  FNLOGC(std::cout, v_ > 0) << "Creating file " << f.first << "\n";
136  TFile file(f.first.c_str(), "RECREATE");
137 
138  // Filter CH instance to leave only the objects that will be written into
139  // this file
140  CombineHarvester f_cmb = cmb.cp().FilterAll([&](ch::Object const* obj) {
141  return !ch::contains(f.second, root_map.at(obj));
142  });
143 
144  // Call BuildMap again - this time to figure out which text datacards to
145  // create
146  auto d_map = BuildMap(text_pattern_, f_cmb);
147 
148  // Create dirs if we're allowed to
149  if (create_dirs_) MakeDirs(d_map);
150 
151  // Loop through each datacard
152  for (auto const& d : d_map) {
153  // Filter CH instance to leave only the objects that will be written into
154  // this text datacard
155  CombineHarvester d_cmb = f_cmb.cp().FilterAll([&](ch::Object const* obj) {
156  return !ch::contains(d.second, text_map.at(obj));
157  });
158  FNLOGC(std::cout, v_ > 0) << "Creating datacard " << d.first << "\n";
159  d_cmb.WriteDatacard(d.first, file);
160  datacards[d.first] = d_cmb;
161  }
162  };
163  return datacards;
164 }
165 
166 std::string CardWriter::Compile(std::string pattern, ch::Object const* obj,
167  bool skip_mass) const {
168  #ifdef TIME_FUNCTIONS
169  LAUNCH_FUNCTION_TIMER(__timer__, __token__)
170  #endif
171  boost::replace_all(pattern, "$TAG", tag_);
172  boost::replace_all(pattern, "$BINID",
173  boost::lexical_cast<std::string>(obj->bin_id()));
174  boost::replace_all(pattern, "$BIN", obj->bin());
175  boost::replace_all(pattern, "$PROCESS", obj->process());
176  if (!skip_mass) boost::replace_all(pattern, "$MASS", obj->mass());
177  boost::replace_all(pattern, "$ERA", obj->era());
178  boost::replace_all(pattern, "$CHANNEL", obj->channel());
179  boost::replace_all(pattern, "$ANALYSIS", obj->analysis());
180  return pattern;
181 }
182 }
#define FNLOGC(x, y)
Definition: Logging.h:14
#define LAUNCH_FUNCTION_TIMER(x, y)
Conveniently initialise a ch::FnTimer instance.
Definition: Logging.h:67
Automates the writing of datacards into directory structures.
Definition: CardWriter.h:50
CardWriter & CreateDirectories(bool flag)
Control whether directories can be created if missing.
Definition: CardWriter.cc:25
CardWriter & SetWildcardMasses(std::vector< std::string > const &masses)
Redefine the mass values that should be treated as wildcards.
Definition: CardWriter.cc:31
std::map< std::string, CombineHarvester > WriteCards(std::string const &tag, ch::CombineHarvester &cmb) const
Write datacards according to patterns, substituting $TAG for tag
Definition: CardWriter.cc:96
CardWriter & SetVerbosity(unsigned v)
Set >= 1 for verbose output, otherwise silent.
Definition: CardWriter.cc:20
CardWriter(std::string const &text_pattern, std::string const &root_pattern)
Must be constructed with text and ROOT file patterns.
Definition: CardWriter.cc:12
void WriteDatacard(std::string const &name, std::string const &root_file)
CombineHarvester & FilterAll(Function func)
CombineHarvester cp()
Creates and returns a shallow copy of the CombineHarvester instance.
void ForEachObj(Function func)
virtual std::string const & process() const
Definition: Object.h:20
virtual std::string const & bin() const
Definition: Object.h:17
virtual int bin_id() const
Definition: Object.h:35
virtual std::string const & analysis() const
Definition: Object.h:26
virtual std::string const & era() const
Definition: Object.h:29
virtual std::string const & mass() const
Definition: Object.h:38
virtual std::string const & channel() const
Definition: Object.h:32
Definition: Algorithm.h:10
bool contains(const Range &r, T p)
Definition: Algorithm.h:22