CMS 3D CMS Logo

DD4hep_TrackingMaterialAnalyser.cc
Go to the documentation of this file.
1 #include <iostream> // FIXME: switch to MessagLogger & friends
2 #include <fstream>
3 #include <sstream>
4 #include <vector>
5 #include <string>
6 #include <stdexcept>
7 #include <cstring>
8 #include <cstdlib>
9 #include <fmt/printf.h>
10 
17 
20 
25 
26 //-------------------------------------------------------------------------
29  consumes<std::vector<MaterialAccountingTrack> >(iPSet.getParameter<edm::InputTag>("MaterialAccounting"));
30  m_groupNames = iPSet.getParameter<std::vector<std::string> >("Groups");
31  const std::string& splitmode = iPSet.getParameter<std::string>("SplitMode");
32  if (strcasecmp(splitmode.c_str(), "NearestLayer") == 0) {
34  } else if (strcasecmp(splitmode.c_str(), "InnerLayer") == 0) {
36  } else if (strcasecmp(splitmode.c_str(), "OuterLayer") == 0) {
38  } else {
41  << "Invalid SplitMode \"" << splitmode
42  << "\". Acceptable values are \"NearestLayer\", \"InnerLayer\", \"OuterLayer\".";
43  }
44  m_dddToken = esConsumes(iPSet.getParameter<edm::ESInputTag>("DDDetector"));
45  m_skipAfterLastDetector = iPSet.getParameter<bool>("SkipAfterLastDetector");
46  m_skipBeforeFirstDetector = iPSet.getParameter<bool>("SkipBeforeFirstDetector");
47  m_saveSummaryPlot = iPSet.getParameter<bool>("SaveSummaryPlot");
48  m_saveDetailedPlots = iPSet.getParameter<bool>("SaveDetailedPlots");
49  m_saveParameters = iPSet.getParameter<bool>("SaveParameters");
50  m_saveXml = iPSet.getParameter<bool>("SaveXML");
51  m_isHGCal = iPSet.getParameter<bool>("isHGCal");
52  m_isHFNose = iPSet.getParameter<bool>("isHFNose");
53  if (m_saveSummaryPlot) {
54  if (m_isHGCal) {
55  m_plotter = std::make_unique<DD4hep_TrackingMaterialPlotter>(550., 300., 10);
56  } else if (m_isHFNose) {
57  m_plotter = std::make_unique<DD4hep_TrackingMaterialPlotter>(1200., 350., 10);
58  } else {
59  m_plotter = std::make_unique<DD4hep_TrackingMaterialPlotter>(300., 120., 10);
60  } // 10x10 points per cm2
61  } else {
62  m_plotter = nullptr;
63  }
64 }
65 
66 //-------------------------------------------------------------------------
68 
69 //-------------------------------------------------------------------------
71  std::ofstream parameters(name);
72  edm::LogVerbatim("TrackerMaterialAnalysis") << "TrackingMaterialAnalyser" << std::endl;
73  for (unsigned int i = 0; i < m_groups.size(); ++i) {
75  edm::LogVerbatim("TrackerMaterialAnalysis") << "TrackingMaterialAnalyser" << layer.name() << std::endl;
76  edm::LogVerbatim("TrackerMaterialAnalysis")
77  << "TrackingMaterialAnalyser" << fmt::sprintf("\tnumber of hits: %9d", layer.tracks())
78  << std::endl;
79  edm::LogVerbatim("TrackerMaterialAnalysis")
80  << "TrackingMaterialAnalyser"
81  << fmt::sprintf("\tnormalized segment length: %9.1f ± %9.1f cm", layer.averageLength(), layer.sigmaLength())
82  << std::endl;
83  edm::LogVerbatim("TrackerMaterialAnalysis") << "TrackingMaterialAnalyser"
84  << fmt::sprintf("\tnormalized radiation lengths: %9.3f ± %9.3f",
85  layer.averageRadiationLengths(),
86  layer.sigmaRadiationLengths())
87  << std::endl;
88  edm::LogVerbatim("TrackerMaterialAnalysis")
89  << "TrackingMaterialAnalyser"
90  << fmt::sprintf("\tnormalized energy loss: %6.5fe-03 ± %6.5fe-03 GeV",
91  layer.averageEnergyLoss(),
92  layer.sigmaEnergyLoss())
93  << std::endl;
94  parameters << fmt::sprintf("%-20s\t%7d\t%5.1f ± %5.1f cm\t%6.4f ± %6.4f \t%6.4fe-03 ± %6.4fe-03 GeV",
95  layer.name(),
96  layer.tracks(),
97  layer.averageLength(),
98  layer.sigmaLength(),
99  layer.averageRadiationLengths(),
100  layer.sigmaRadiationLengths(),
101  layer.averageEnergyLoss(),
102  layer.sigmaEnergyLoss())
103  << std::endl;
104  }
105  edm::LogVerbatim("TrackerMaterialAnalysis") << "TrackingMaterialAnalyser" << std::endl;
106 
107  parameters.close();
108 }
109 
110 //-------------------------------------------------------------------------
112  std::ofstream xml(name);
113  xml << "<?xml version=\"1.0\" encoding=\"utf-8\"?>" << std::endl;
114  xml << "<Groups>" << std::endl;
115  for (unsigned int i = 0; i < m_groups.size(); ++i) {
117  xml << " <Group name=\"" << layer.name() << "\">\n"
118  << " <Parameter name=\"TrackerRadLength\" value=\"" << layer.averageRadiationLengths() << "\"/>\n"
119  << " <Parameter name=\"TrackerXi\" value=\"" << layer.averageEnergyLoss() << "\"/>\n"
120  << " </Group>\n"
121  << std::endl;
122  }
123  xml << "</Groups>" << std::endl;
124 }
125 
126 //-------------------------------------------------------------------------
128  for (unsigned int i = 0; i < m_groups.size(); ++i) {
130  layer.savePlots();
131  }
132 }
133 
134 //-------------------------------------------------------------------------
136  if (m_saveParameters)
137  saveParameters("parameters");
138 
139  if (m_saveXml)
140  saveXml("parameters.xml");
141 
143  saveLayerPlots();
144 
145  if (m_saveSummaryPlot and m_plotter) {
146  m_plotter->normalize();
147  m_plotter->draw();
148  }
149 }
150 
151 //-------------------------------------------------------------------------
152 
153 //-------------------------------------------------------------------------
155  using namespace edm;
156  auto hDDD = setup.getTransientHandle(m_dddToken);
157 
158  m_groups.reserve(m_groupNames.size());
159  // Initialize m_groups iff it has size equal to zero, so that we are
160  // sure it will never be repopulated with the same entries over and
161  // over again in the eventloop, at each call of the analyze method.
162  if (m_groups.empty()) {
163  for (unsigned int i = 0; i < m_groupNames.size(); ++i)
164  m_groups.emplace_back(new DD4hep_MaterialAccountingGroup(m_groupNames[i], *hDDD));
165 
166  edm::LogVerbatim("TrackerMaterialAnalysis")
167  << "TrackingMaterialAnalyser: List of the tracker groups: " << std::endl;
168  for (unsigned int i = 0; i < m_groups.size(); ++i)
169  edm::LogVerbatim("TrackerMaterialAnalysis")
170  << i << " TrackingMaterialAnalyser:\t" << m_groups[i]->info() << std::endl;
171  }
173  event.getByToken(m_materialToken, h_tracks);
174 
175  for (std::vector<MaterialAccountingTrack>::const_iterator t = h_tracks->begin(), end = h_tracks->end(); t != end;
176  ++t) {
178  split(track);
179  }
180 }
181 
182 //-------------------------------------------------------------------
183 // split a track in segments, each associated to a sensitive detector
184 // in a DetLayer; then, associate each step to one segment, splitting
185 // the steps across the segment boundaries
186 //
187 // Nota Bene: this implementation assumes that the steps stored along
188 // each track are consecutive and adjacent, and that no step can span
189 // across 3 layers, since all steps should split at layer boundaries
190 
192  using namespace edm;
193  // group sensitive detectors by their DetLayer
194  std::vector<int> group(track.detectors().size());
195  for (unsigned int i = 0; i < track.detectors().size(); ++i)
196  group[i] = findLayer(track.detectors()[i]);
197 
198  for (unsigned int i = 0; i < group.size(); ++i)
199  if (group[i] > 0)
200  edm::LogVerbatim("TrackerMaterialAnalysis") << "TrackingMaterialAnalyser:\n"
201  << "For detector i: " << i << " index: " << group[i]
202  << " R-ranges: " << m_groups[group[i] - 1]->getBoundingR().first
203  << ", " << m_groups[group[i] - 1]->getBoundingR().second << group[i]
204  << " Z-ranges: " << m_groups[group[i] - 1]->getBoundingZ().first
205  << ", " << m_groups[group[i] - 1]->getBoundingZ().second << std::endl;
206 
207  unsigned int detectors = track.detectors().size();
208  if (detectors == 0) {
209  // the track doesn't cross any active detector:
210  // keep al material as unassigned
211  if (m_plotter)
212  for (unsigned int i = 1; i < track.steps().size(); ++i)
213  m_plotter->plotSegmentUnassigned(track.steps()[i]);
214  } else {
215  const double TOLERANCE = 0.0001; // 1 um tolerance
216  std::vector<double> limits(detectors + 2);
217 
218  // define the trivial limits
220  limits[0] = track.detectors()[0].m_curvilinearIn - TOLERANCE;
221  else
222  limits[0] = -TOLERANCE;
224  limits[detectors] = track.detectors()[detectors - 1].m_curvilinearOut + TOLERANCE;
225  else
226  limits[detectors] = track.summary().length() + TOLERANCE;
227  limits[detectors + 1] = INFINITY; // this is probably no more needed, but doesn't harm...
228 
229  // pick the algorithm to define the non-trivial limits
230  switch (m_splitMode) {
231  // assign each segment to the the nearest layer
232  // e.g. the material between pixel barrel 3 and TIB 1 will be split among the two
233  case NEAREST_LAYER:
234  for (unsigned int i = 1; i < detectors; ++i) {
235  limits[i] = (track.detectors()[i - 1].m_curvilinearOut + track.detectors()[i].m_curvilinearIn) / 2.;
236  }
237  break;
238 
239  // assign each segment to the the inner layer
240  // e.g. all material between pixel barrel 3 and TIB 1 will go into the pixel barrel
241  case INNER_LAYER:
242  for (unsigned int i = 1; i < detectors; ++i)
243  limits[i] = track.detectors()[i].m_curvilinearIn - TOLERANCE;
244  break;
245 
246  // assign each segment to the the outer layer
247  // e.g. all material between pixel barrel 3 and TIB 1 will go into the TIB
248  case OUTER_LAYER:
249  for (unsigned int i = 1; i < detectors; ++i)
250  limits[i] = track.detectors()[i - 1].m_curvilinearOut + TOLERANCE;
251  break;
252 
253  case UNDEFINED:
254  [[fallthrough]];
255 
256  default:
257  // throw something
258  throw edm::Exception(edm::errors::LogicError) << "Invalid SplitMode";
259  }
260 
261  double begin = 0.; // beginning of step, along the track
262  double end = 0.; // end of step, along the track
263  unsigned int i = 1; // step conter
264 
265  // skip the material before the first layer
266  while (end < limits[0]) {
267  const MaterialAccountingStep& step = track.steps()[i++];
268  end = begin + step.length();
269 
270  // do not account material before the first layer
271  if (m_plotter)
272  m_plotter->plotSegmentUnassigned(step);
273 
274  begin = end;
275  }
276 
277  unsigned int index = 0; // which detector
278  while (i < track.steps().size()) {
279  const MaterialAccountingStep& step = track.steps()[i++];
280 
281  end = begin + step.length();
282 
283  if (begin > limits[detectors]) {
284  // segment after last layer and skipping requested in configuation
285  if (m_plotter)
286  m_plotter->plotSegmentUnassigned(step);
287  begin = end;
288  continue;
289  }
290 
291  // from here onwards we should be in the accountable region, either completely in a single layer:
292  // limits[index] <= begin < end <= limits[index+1]
293  // or possibly split between 2 layers
294  // limits[index] < begin < limits[index+1] < end < limits[index+2]
295  if (begin < limits[index] or end > limits[index + 2]) {
296  // sanity check
297  edm::LogError("TrackerMaterialAnalysis")
298  << "TrackingMaterialAnalyser::split(): ERROR: internal logic error, expected " << limits[index] << " < "
299  << begin << " < " << limits[index + 1] << std::endl;
300  break;
301  }
302 
303  if (limits[index] <= begin and end <= limits[index + 1]) {
304  // step completely inside current detector range
305  track.detectors()[index].account(step, begin, end);
306  if (m_plotter)
307  m_plotter->plotSegmentInLayer(step, group[index]);
308  } else {
309  // step shared beteewn two detectors, transition at limits[index+1]
310  double fraction = (limits[index + 1] - begin) / (end - begin);
311  assert(fraction < 1.);
312  std::pair<MaterialAccountingStep, MaterialAccountingStep> parts = step.split(fraction);
313 
314  if (m_plotter) {
315  if (index > 0)
316  m_plotter->plotSegmentInLayer(parts.first, group[index]);
317  else
318  // track outside acceptance, keep as unassocated
319  m_plotter->plotSegmentUnassigned(parts.first);
320 
321  if (index + 1 < detectors)
322  m_plotter->plotSegmentInLayer(parts.second, group[index + 1]);
323  else
324  // track outside acceptance, keep as unassocated
325  m_plotter->plotSegmentUnassigned(parts.second);
326  }
327 
328  track.detectors()[index].account(parts.first, begin, limits[index + 1]);
329  ++index; // next layer
330  if (index < detectors)
331  track.detectors()[index].account(parts.second, limits[index + 1], end);
332  }
333  begin = end;
334  }
335  }
336 
337  // add the material from each detector to its layer (if there is one and only one)
338  for (unsigned int i = 0; i < track.detectors().size(); ++i)
339  if (group[i] != 0)
340  m_groups[group[i] - 1]->addDetector(track.detectors()[i]);
341 
342  // end of track: commit internal buffers and reset the m_groups internal state for a new track
343  for (unsigned int i = 0; i < m_groups.size(); ++i)
344  m_groups[i]->endOfTrack();
345 }
346 
347 //-------------------------------------------------------------------------
348 // find the layer index (0: none, 1-3: PixelBarrel,
349 // 4-7: TID, 8-13: TOB, 14-15,28-29: PixelEndcap,
350 // 16-18,30-32: TID, 19-27,33-41: TEC)
352  int index = 0;
353  size_t inside = 0;
354  for (size_t i = 0; i < m_groups.size(); ++i)
355  if (m_groups[i]->isInside(detector)) {
356  ++inside;
357  index = i + 1;
358  }
359  if (inside == 0) {
360  index = 0;
361  edm::LogError("TrackerMaterialAnalysis")
362  << "TrackingMaterialAnalyser::findLayer(...): ERROR: detector does not belong to any DetLayer" << std::endl;
363  edm::LogError("TrackerMaterialAnalysis")
364  << "TrackingMaterialAnalyser::findLayer(...): detector position: " << std::fixed
365  << " (r: " << std::setprecision(1) << std::setw(5) << detector.position().perp()
366  << ", z: " << std::setprecision(1) << std::setw(6) << detector.position().z()
367  << ", phi: " << std::setprecision(3) << std::setw(6) << detector.position().phi() << ")" << std::endl;
368  }
369  if (inside > 1) {
370  index = 0;
371  edm::LogError("TrackerMaterialAnalysis") << "TrackingMaterialAnalyser::findLayer(...): ERROR: detector belongs to "
372  << inside << " DetLayers" << std::endl;
373  edm::LogError("TrackerMaterialAnalysis")
374  << "TrackingMaterialAnalyser::findLayer(...): detector position: " << std::fixed
375  << " (r: " << std::setprecision(1) << std::setw(5) << detector.position().perp()
376  << ", z: " << std::setprecision(1) << std::setw(6) << detector.position().z()
377  << ", phi: " << std::setprecision(3) << std::setw(6) << detector.position().phi() << ")" << std::endl;
378  }
379 
380  return index;
381 }
382 
383 //-------------------------------------------------------------------------
384 // define as a plugin
Log< level::Info, true > LogVerbatim
void analyze(const edm::Event &, const edm::EventSetup &) override
void split(MaterialAccountingTrack &track)
T getParameter(std::string const &) const
Definition: ParameterSet.h:303
std::unique_ptr< DD4hep_TrackingMaterialPlotter > m_plotter
edm::ESGetToken< cms::DDCompactView, IdealGeometryRecord > m_dddToken
DD4hep_TrackingMaterialAnalyser(const edm::ParameterSet &)
#define DEFINE_FWK_MODULE(type)
Definition: MakerMacros.h:16
std::vector< DD4hep_MaterialAccountingGroup * > m_groups
Log< level::Error, false > LogError
assert(be >=bs)
edm::EDGetTokenT< std::vector< MaterialAccountingTrack > > m_materialToken
constexpr std::array< uint8_t, layerIndexSize > layer
int findLayer(const MaterialAccountingDetector &detector)
def detectors(dt=True, csc=True, me42=False, chambers=True, superlayers=False, layers=False)
The Signals That Services Can Subscribe To This is based on ActivityRegistry and is current per Services can connect to the signals distributed by the ActivityRegistry in order to monitor the activity of the application Each possible callback has some defined which we here list in angle e< void, edm::EventID const &, edm::Timestamp const & > We also list in braces which AR_WATCH_USING_METHOD_ is used for those or
Definition: Activities.doc:12
HLT enums.
step
Definition: StallMonitor.cc:98
Definition: event.py:1