All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
GeometryInfoCheck_module.cc
Go to the documentation of this file.
1 /**
2  * @file GeometryInfoCheck_module.cc
3  * @brief Verifies that the geometry check information is available in the run.
4  * @author Gianluca Petrillo (petrillo@slac.stanford.edu)
5  * @date November 11, 2020
6  */
7 
8 // LArSoft libraries
12 
13 // framework libraries
14 #include "art/Framework/Core/ModuleMacros.h"
15 #include "art/Framework/Core/EDAnalyzer.h"
16 #include "art/Framework/Principal/Run.h"
17 #include "art/Framework/Principal/Handle.h"
18 #include "art/Framework/Principal/Provenance.h"
19 #include "canvas/Utilities/InputTag.h"
20 #include "messagefacility/MessageLogger/MessageLogger.h"
21 #include "fhiclcpp/types/OptionalTable.h"
22 #include "fhiclcpp/types/OptionalAtom.h"
23 #include "fhiclcpp/types/Atom.h"
24 #include "cetlib_except/exception.h"
25 
26 // C/C++ standard library
27 #include <vector>
28 #include <string>
29 #include <optional>
30 #include <utility> // std::move()
31 
32 // -----------------------------------------------------------------------------
33 namespace art { class Event; }
34 
35 // -----------------------------------------------------------------------------
36 /**
37  * @brief Verifies that the geometry check information is available.
38  *
39  * Configuration parameters
40  * =========================
41  *
42  */
43 namespace geo { class GeometryInfoCheck; }
44 class geo::GeometryInfoCheck: public art::EDAnalyzer {
45  public:
46 
48 
49  fhicl::OptionalAtom<std::string> Name {
50  fhicl::Name{ "Name" },
51  fhicl::Comment{ "Name of the geometry (if omitted, any will do)" }
52  };
53 
54  fhicl::Atom<bool> Required {
55  fhicl::Name{ "Required" },
56  fhicl::Comment{ "Whether the presence of this item is mandatory" },
57  true
58  };
59 
60  }; // struct GeometryInfoConfig
61 
62 
63  struct Config {
64 
65  fhicl::OptionalTable<GeometryInfoConfig> GeometryInfo {
66  fhicl::Name{ "GeometryInfo" },
67  fhicl::Comment{ "Information to check about geometry" }
68  };
69 
70  fhicl::OptionalTable<GeometryInfoConfig> GeometryLegacyInfo {
71  fhicl::Name{ "LegacyInfo" },
72  fhicl::Comment
73  { "Information to check about geometry (legacy from RunData)" }
74  };
75 
76  }; // struct Config
77 
78  using Parameters = art::EDAnalyzer::Table<Config>;
79 
80  explicit GeometryInfoCheck(Parameters const& config);
81 
82  virtual void beginRun(art::Run const& run) override;
83 
84  virtual void analyze(art::Event const&) override {}
85 
86  private:
87 
89  bool required; ///< Whether the information must be present.
90  std::string detectorName; ///< Name of the detector; empty: don't check.
91  };
92 
93  /// Information on the check on the regular geometry information.
94  std::optional<GeometryInfoCheckInfo> fCheckInfo;
95 
96  /// Information on the check on the legacy geometry information.
97  std::optional<GeometryInfoCheckInfo> fLegacyCheckInfo;
98 
99  /// Performs a geometry information check.
100  /// @throw cet::exception on check failures
101  void CheckGeometryInfo
102  (art::Run const& run, GeometryInfoCheckInfo const& config) const;
103 
104  /// Performs a legacy geometry information check
105  /// @throw cet::exception on check failures
107  (art::Run const& run, GeometryInfoCheckInfo const& config) const;
108 
109 
110  /// The name of the tag for the geometry information.
111  static art::InputTag const GeometryConfigurationWriterTag;
112 
113  /// Fills a `GeometryInfoCheckInfo` out of the specified configuration.
114  static std::optional<GeometryInfoCheckInfo> makeGeometryInfoCheckInfo
115  (fhicl::OptionalTable<GeometryInfoConfig> const& config);
116 
117 }; // class geo::GeometryInfoCheck
118 
119 
120 // -----------------------------------------------------------------------------
121 // --- geo::GeometryInfoCheck implementation
122 // -----------------------------------------------------------------------------
123 
124 namespace {
125 
126  bool case_insensitive_equal(std::string const& a, std::string const& b) {
127 
128  return std::equal(a.begin(), a.end(), b.begin(), b.end(),
129  [](auto a, auto b)
130  {
131  return ::tolower(static_cast<unsigned char>(a))
132  == ::tolower(static_cast<unsigned char>(b));
133  }
134  );
135 
136  } // case_insensitive_equal()
137 
138 } // local namespace
139 
140 // -----------------------------------------------------------------------------
142  { "GeometryConfigurationWriter" };
143 
144 
145 // -----------------------------------------------------------------------------
147  : art::EDAnalyzer(config)
148  , fCheckInfo(makeGeometryInfoCheckInfo(config().GeometryInfo))
149  , fLegacyCheckInfo(makeGeometryInfoCheckInfo(config().GeometryLegacyInfo))
150 {
151 
152  if (fCheckInfo)
153  consumes<sumdata::GeometryConfigurationInfo>(GeometryConfigurationWriterTag);
154  if (fLegacyCheckInfo) consumesMany<sumdata::RunData>();
155 
156 
157  // --- BEGIN -- Configuration dump -------------------------------------------
158  {
159  mf::LogDebug log { "GeometryInfoCheck" };
160  log << "Configuration:"
161  << "\n - geometry configuration check:";
162  if (fCheckInfo) {
163  if (fCheckInfo->detectorName.empty()) log << " (any name)";
164  else log << " must match '" << fCheckInfo->detectorName << "'";
165  log << " [" << (fCheckInfo->required? "mandatory": "optional") << "]";
166  }
167  else log << "not requested";
168 
169  log << "\n - legacy geometry configuration information check:";
170  if (fLegacyCheckInfo) {
171  if (fLegacyCheckInfo->detectorName.empty()) log << " (any name)";
172  else log << " must match '" << fLegacyCheckInfo->detectorName << "'";
173  log << " [" << (fLegacyCheckInfo->required? "mandatory": "optional") << "]";
174  }
175  else log << "not requested";
176 
177  }
178  // --- END -- Configuration dump ---------------------------------------------
179 
180 } // geo::GeometryInfoCheck::GeometryInfoCheck()
181 
182 
183 // -----------------------------------------------------------------------------
184 void geo::GeometryInfoCheck::beginRun(art::Run const& run) {
185 
186  if (fCheckInfo) CheckGeometryInfo(run, fCheckInfo.value());
187  if (fLegacyCheckInfo) CheckLegacyGeometryInfo(run, fLegacyCheckInfo.value());
188 
189 } // geo::GeometryInfoCheck::beginRun()
190 
191 
192 // -----------------------------------------------------------------------------
194  (art::Run const& run, GeometryInfoCheckInfo const& config) const
195 {
196 
197  mf::LogDebug log { "GeometryInfoCheck" };
198  log << "Check on geometry information.";
199 
200  //
201  // fetch geometry information
202  //
203  art::Handle<sumdata::GeometryConfigurationInfo> hInfo;
204  if (!run.getByLabel(GeometryConfigurationWriterTag, hInfo)) {
205  log << "\nNo information found.";
206  if (!config.required) return; // well... all ok?
207 
208  log << "\nUnfortunately, that was required...";
209  throw cet::exception("GeometryInfoCheck")
210  << "Required geometry information not found as '"
211  << GeometryConfigurationWriterTag.encode() << "'\n";
212  } // if no info
213 
214  sumdata::GeometryConfigurationInfo const& info { *hInfo };
215  log
216  << "\nFound geometry information (version " << info.dataVersion << ")"
217  << " from '" << hInfo.provenance()->inputTag().encode() << "'"
218  << "\nGeometry name is '" << info.detectorName << "'."
219  ;
220 
221  //
222  // check: the name
223  //
224  if (!config.detectorName.empty()
225  && !case_insensitive_equal(info.detectorName, config.detectorName)
226  ) {
227  throw cet::exception("GeometryInfoCheck")
228  << "Geometry information reports an unexpected name '"
229  << info.detectorName << "' ('" << config.detectorName << "' expected)\n"
230  ;
231  } // if
232 
233  //
234  // all checks done
235  //
236 
237 } // geo::GeometryInfoCheck::CheckGeometryInfo()
238 
239 
240 // -----------------------------------------------------------------------------
242  (art::Run const& run, GeometryInfoCheckInfo const& config) const
243 {
244 
245  mf::LogDebug log { "GeometryInfoCheck" };
246  log << "Check on legacy geometry information.";
247 
248  //
249  // fetch geometry information
250  //
251  //std::vector<art::Handle<sumdata::RunData>> hInfoList;
252  //run.getManyByType(hInfoList);
253  auto hInfoList = run.getMany<sumdata::RunData>();
254  if (hInfoList.empty()) {
255  log << "\nNo information found.";
256  if (!config.required) return; // well... all ok?
257 
258  log << "\nUnfortunately, that was required...";
259  throw cet::exception("GeometryInfoCheck")
260  << "No legacy geometry information found!\n";
261  } // if no info
262 
263  log << "\nFound " << hInfoList.size() << " legacy geometry records:";
264  art::Handle<sumdata::RunData> const* hInfo = nullptr;
265  for (auto const& handle: hInfoList) {
266  log << "\n - " << handle.provenance()->inputTag().encode();
267  if (handle.failedToGet()) log << " (not present)";
268  else if (!hInfo) {
269  hInfo = &handle;
270  log << " (this will be used for the check)";
271  }
272  } // for all handles
273 
274  sumdata::RunData const& info { *(hInfo->product()) };
275  log
276  << "\nFound legacy geometry information "
277  << "\nGeometry name is '" << info.DetName() << "'."
278  ;
279 
280  //
281  // check: the name
282  //
283  if (!config.detectorName.empty()
284  && !case_insensitive_equal(info.DetName(), config.detectorName)
285  ) {
286  throw cet::exception("GeometryInfoCheck")
287  << "Geometry legacy information reports an unexpected name '"
288  << info.DetName() << "' ('" << config.detectorName << "' expected)\n"
289  ;
290  } // if
291 
292  //
293  // all checks done
294  //
295 
296 } // geo::GeometryInfoCheck::CheckLegacyGeometryInfo()
297 
298 
299 // -----------------------------------------------------------------------------
301  (fhicl::OptionalTable<GeometryInfoConfig> const& config)
302  -> std::optional<GeometryInfoCheckInfo>
303 {
304  GeometryInfoConfig infoConfig;
305  if (!config(infoConfig)) return {};
306 
308  info.required = infoConfig.Required();
309  infoConfig.Name(info.detectorName); // so far, not specifying it defaults to empty
310 
311  return { std::move(info) };
312 } // geo::GeometryInfoCheck::makeGeometryInfoCheckInfo()
313 
314 
315 // -----------------------------------------------------------------------------
316 DEFINE_ART_MODULE(geo::GeometryInfoCheck)
317 
318 
319 // -----------------------------------------------------------------------------
GeometryInfoCheck(Parameters const &config)
void CheckLegacyGeometryInfo(art::Run const &run, GeometryInfoCheckInfo const &config) const
static std::optional< GeometryInfoCheckInfo > makeGeometryInfoCheckInfo(fhicl::OptionalTable< GeometryInfoConfig > const &config)
Fills a GeometryInfoCheckInfo out of the specified configuration.
fhicl::OptionalTable< GeometryInfoConfig > GeometryLegacyInfo
process_name gaushit a
virtual void beginRun(art::Run const &run) override
BEGIN_PROLOG vertical distance to the surface Name
bool equal(double a, double b)
Comparison tolerance, in centimeters.
Description of the current configuration of detector geometry.
art::EDAnalyzer::Table< Config > Parameters
std::string detectorName
Name of the detector; empty: don&#39;t check.
bool required
Whether the information must be present.
std::optional< GeometryInfoCheckInfo > fLegacyCheckInfo
Information on the check on the legacy geometry information.
static art::InputTag const GeometryConfigurationWriterTag
The name of the tag for the geometry information.
void CheckGeometryInfo(art::Run const &run, GeometryInfoCheckInfo const &config) const
virtual void analyze(art::Event const &) override
art framework interface to geometry description
Description of the current configuration of detector geometry.
fhicl::OptionalTable< GeometryInfoConfig > GeometryInfo
std::optional< GeometryInfoCheckInfo > fCheckInfo
Information on the check on the regular geometry information.