CMS 3D CMS Logo

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