CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
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/tuple/tuple.hpp>
10 #include <boost/format.hpp>
11 
17 
22 
28 
29 //-------------------------------------------------------------------------
31 {
32  m_material = iPSet.getParameter<edm::InputTag>("MaterialAccounting");
33  m_groupNames = iPSet.getParameter<std::vector<std::string> >("Groups");
34  const std::string & splitmode = iPSet.getParameter<std::string>("SplitMode");
35  if (strcasecmp(splitmode.c_str(), "NearestLayer") == 0) {
37  } else if (strcasecmp(splitmode.c_str(), "InnerLayer") == 0) {
39  } else if (strcasecmp(splitmode.c_str(), "OuterLayer") == 0) {
41  } else {
43  throw edm::Exception(edm::errors::LogicError) << "Invalid SplitMode \"" << splitmode << "\". Acceptable values are \"NearestLayer\", \"InnerLayer\", \"OuterLayer\".";
44  }
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  if (m_saveSummaryPlot)
52  m_plotter = new TrackingMaterialPlotter( 300., 120., 10 ); // 10x10 points per cm2
53  else
54  m_plotter = NULL;
55 }
56 
57 //-------------------------------------------------------------------------
59 {
60  if (m_plotter)
61  delete m_plotter;
62 }
63 
64 //-------------------------------------------------------------------------
66 {
67  std::ofstream parameters(name);
68  std::cout << std::endl;
69  for (unsigned int i = 0; i < m_groups.size(); ++i) {
70  MaterialAccountingGroup & layer = *(m_groups[i]);
71  std::cout << layer.name() << std::endl;
72  std::cout << boost::format("\tnumber of hits: %9d") % layer.tracks() << std::endl;
73  std::cout << boost::format("\tnormalized segment length: %9.1f ± %9.1f cm") % layer.averageLength() % layer.sigmaLength() << std::endl;
74  std::cout << boost::format("\tnormalized radiation lengths: %9.3f ± %9.3f") % layer.averageRadiationLengths() % layer.sigmaRadiationLengths() << std::endl;
75  std::cout << boost::format("\tnormalized energy loss: %9.3f ± %9.3f MeV") % layer.averageEnergyLoss() % layer.sigmaEnergyLoss() << std::endl;
76  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")
77  % layer.name()
78  % layer.tracks()
79  % layer.averageLength() % layer.sigmaLength()
81  % layer.averageEnergyLoss() % layer.sigmaEnergyLoss()
82  << std::endl;
83  }
84  std::cout << std::endl;
85 
86  parameters.close();
87 }
88 
89 //-------------------------------------------------------------------------
91 {
92  std::ofstream xml(name);
93  xml << "<?xml version=\"1.0\" encoding=\"utf-8\"?>" << std::endl;
94  xml << "<Groups>" << std::endl;
95  for (unsigned int i = 0; i < m_groups.size(); ++i) {
96  MaterialAccountingGroup & layer = *(m_groups[i]);
97  xml << " <Group name=\"" << layer.name() << "\">\n"
98  << " <Parameter name=\"TrackerRadLength\" value=\"" << layer.averageRadiationLengths() << "\"/>\n"
99  << " <Parameter name=\"TrackerXi\" value=\"" << layer.averageEnergyLoss() << "\"/>\n"
100  << " </Group>\n"
101  << std::endl;
102  }
103  xml << "</Groups>" << std::endl;
104 }
105 
106 //-------------------------------------------------------------------------
108 {
109  for (unsigned int i = 0; i < m_groups.size(); ++i) {
110  MaterialAccountingGroup & layer = *(m_groups[i]);
111  layer.savePlots();
112  }
113 }
114 
115 //-------------------------------------------------------------------------
117 {
118  if (m_saveParameters)
119  saveParameters("parameters");
120 
121  if (m_saveXml)
122  saveXml("parameters.xml");
123 
125  saveLayerPlots();
126 
127  if (m_saveSummaryPlot and m_plotter) {
128  m_plotter->normalize();
129  m_plotter->draw();
130  }
131 }
132 
133 //-------------------------------------------------------------------------
134 
135 //-------------------------------------------------------------------------
137 {
139  setup.get<IdealGeometryRecord>().get( hDDD );
140 
141  m_groups.reserve( m_groupNames.size() );
142  for (unsigned int i = 0; i < m_groupNames.size(); ++i)
143  m_groups.push_back( new MaterialAccountingGroup( m_groupNames[i], * hDDD) );
144 
145  // INFO
146  std::cout << "TrackingMaterialAnalyser: List of the tracker groups: " << std::endl;
147  for (unsigned int i = 0; i < m_groups.size(); ++i)
148  std::cout << '\t' << m_groups[i]->info() << std::endl;
149  std::cout << std::endl;
150 
152  event.getByLabel(m_material, h_tracks);
153 
154  for (std::vector<MaterialAccountingTrack>::const_iterator t = h_tracks->begin(), end = h_tracks->end(); t != end; ++t) {
155  MaterialAccountingTrack track(*t);
156  split( track );
157  }
158 }
159 
160 //-------------------------------------------------------------------------
161 // split a track in segments, each associated to a sensitive detector in a DetLayer;
162 // then, associate each step to one segment, splitting the steps across the segment boundaries
163 //
164 // Nota Bene: this implementation assumes that the steps stored along each track are consecutive and adjacent,
165 // and that no step can span across 3 layers, since all steps should split at layer boundaries
166 
168 {
169  // group sensitive detectors by their DetLayer
170  std::vector<int> group( track.m_detectors.size() );
171  for (unsigned int i = 0; i < track.m_detectors.size(); ++i)
172  group[i] = findLayer( track.m_detectors[i] );
173 
174  unsigned int detectors = track.m_detectors.size();
175  if (detectors == 0) {
176  // the track doesn't cross any active detector:
177  // keep al material as unassigned
178  if (m_plotter)
179  for (unsigned int i = 1; i < track.m_steps.size(); ++i)
181  } else {
182  const double TOLERANCE = 0.0001; // 1 um tolerance
183  std::vector<double> limits(detectors + 2);
184 
185  // define the trivial limits
187  limits[0] = track.m_detectors[0].m_curvilinearIn - TOLERANCE;
188  else
189  limits[0] = - TOLERANCE;
191  limits[detectors] = track.m_detectors[detectors-1].m_curvilinearOut + TOLERANCE;
192  else
193  limits[detectors] = track.m_total.length() + TOLERANCE;
194  limits[detectors+1] = INFINITY; // this is probably no more needed, but doesn't harm...
195 
196  // pick the algorithm to define the non-trivial limits
197  switch (m_splitMode) {
198  // assign each segment to the the nearest layer
199  // e.g. the material between pixel barrel 3 and TIB 1 will be split among the two
200  case NEAREST_LAYER:
201  for (unsigned int i = 1; i < detectors; ++i)
202  limits[i] = (track.m_detectors[i-1].m_curvilinearOut + track.m_detectors[i].m_curvilinearIn) / 2.;
203  break;
204 
205  // assign each segment to the the inner layer
206  // e.g. all material between pixel barrel 3 and TIB 1 will go into the pixel barrel
207  case INNER_LAYER:
208  for (unsigned int i = 1; i < detectors; ++i)
209  limits[i] = track.m_detectors[i].m_curvilinearIn - TOLERANCE;
210  break;
211 
212  // assign each segment to the the outer layer
213  // e.g. all material between pixel barrel 3 and TIB 1 will go into the TIB
214  case OUTER_LAYER:
215  for (unsigned int i = 1; i < detectors; ++i)
216  limits[i] = track.m_detectors[i-1].m_curvilinearOut + TOLERANCE;
217  break;
218 
219  case UNDEFINED:
220  default:
221  // throw something
222  throw edm::Exception(edm::errors::LogicError) << "Invalid SplitMode";
223  }
224 
225  //for (unsigned int i = 0; i < detectors; ++i)
226  // std::cout << "MaterialAccountingTrack::split(): detector region boundaries: [" << limits[i] << ", " << limits[i+1] << "] along track" << std::endl;
227 
228  double begin = 0.; // begginning of step, along the track
229  double end = 0.; // end of step, along the track
230  unsigned int i = 1; // step conter
231 
232  // skip the material before the first layer
233  //std::cout << "before first layer, skipping" << std::endl;
234  while (end < limits[0]) {
235  const MaterialAccountingStep & step = track.m_steps[i++];
236  end = begin + step.length();
237 
238  // do not account material before the first layer
239  if (m_plotter)
241 
242  begin = end;
243  //std::cout << '.';
244  }
245  //std::cout << std::endl;
246 
247  // optionally split a step across the first layer boundary
248  //std::cout << "first layer (0): " << limits[0] << ".." << limits[1] << std::endl;
249  if (begin < limits[0] and end > limits[0]) {
250  const MaterialAccountingStep & step = track.m_steps[i++];
251  end = begin + step.length();
252 
253  double fraction = (limits[0] - begin) / (end - begin);
254  std::pair<MaterialAccountingStep, MaterialAccountingStep> parts = step.split(fraction);
255 
256  //std::cout << '!' << std::endl;
257  track.m_detectors[0].account( parts.second, limits[1], end );
258 
259  if (m_plotter) {
260  // step partially before first layer, keep first part as unassocated
261  m_plotter->plotSegmentUnassigned( parts.first );
262 
263  // associate second part to first layer
264  m_plotter->plotSegmentInLayer( parts.second, group[0] );
265  }
266  begin = end;
267  }
268 
269  unsigned int index = 0; // which detector
270  while (i < track.m_steps.size()) {
271  const MaterialAccountingStep & step = track.m_steps[i++];
272 
273  end = begin + step.length();
274 
275  if (begin > limits[detectors]) {
276  // segment after last layer and skipping requested in configuation
277  if (m_plotter)
279  begin = end;
280  continue;
281  }
282 
283  // from here onwards we should be in the accountable region, either completely in a single layer:
284  // limits[index] <= begin < end <= limits[index+1]
285  // or possibly split between 2 layers
286  // limits[index] < begin < limits[index+1] < end < limits[index+2]
287  if (begin < limits[index] or end > limits[index+2]) {
288  // sanity check
289  std::cerr << "MaterialAccountingTrack::split(): ERROR: internal logic error, expected " << limits[index] << " < " << begin << " < " << limits[index+1] << std::endl;
290  break;
291  }
292 
293  //std::cout << '.';
294  if (limits[index] <= begin and end <= limits[index+1]) {
295  // step completely inside current detector range
296  track.m_detectors[index].account( step, begin, end );
297  if (m_plotter)
298  m_plotter->plotSegmentInLayer( step, group[index] );
299  } else {
300  // step shared beteewn two detectors, transition at limits[index+1]
301  double fraction = (limits[index+1] - begin) / (end - begin);
302  std::pair<MaterialAccountingStep, MaterialAccountingStep> parts = step.split(fraction);
303 
304  if (m_plotter) {
305  if (index > 0)
306  m_plotter->plotSegmentInLayer( parts.first, group[index] );
307  else
308  // track outside acceptance, keep as unassocated
309  m_plotter->plotSegmentUnassigned( parts.first );
310 
311  if (index+1 < detectors)
312  m_plotter->plotSegmentInLayer( parts.second, group[index+1] );
313  else
314  // track outside acceptance, keep as unassocated
315  m_plotter->plotSegmentUnassigned( parts.second );
316  }
317 
318  track.m_detectors[index].account( parts.first, begin, limits[index+1] );
319  ++index; // next layer
320  //std::cout << '!' << std::endl;
321  //std::cout << "next layer (" << index << "): " << limits[index] << ".." << limits[index+1] << std::endl;
322  if (index < detectors)
323  track.m_detectors[index].account( parts.second, limits[index+1], end );
324  }
325  begin = end;
326  }
327 
328  }
329  //std::cout << std::endl;
330 
331  // add the material from each detector to its layer (if there is one and only one)
332  for (unsigned int i = 0; i < track.m_detectors.size(); ++i)
333  if (group[i] != 0)
334  m_groups[group[i]-1]->addDetector( track.m_detectors[i] );
335 
336  // end of track: commit internal buffers and reset the m_groups internal state for a new track
337  for (unsigned int i = 0; i < m_groups.size(); ++i)
338  m_groups[i]->endOfTrack();
339 }
340 
341 //-------------------------------------------------------------------------
342 // find the layer index (0: none, 1-3: PixelBarrel, 4-7: TID, 8-13: TOB, 14-15,28-29: PixelEndcap, 16-18,30-32: TID, 19-27,33-41: TEC)
344 {
345  int index = 0;
346  size_t inside = 0;
347  for (size_t i = 0; i < m_groups.size(); ++i)
348  if (m_groups[i]->inside(detector)) {
349  ++inside;
350  index = i+1;
351  }
352  if (inside == 0) {
353  index = 0;
354  std::cerr << "TrackingMaterialAnalyser::findLayer(...): ERROR: detector does not belong to any DetLayer" << std::endl;
355  std::cerr << "TrackingMaterialAnalyser::findLayer(...): detector position: " << std::fixed
356  << " (r: " << std::setprecision(1) << std::setw(5) << detector.position().perp()
357  << ", z: " << std::setprecision(1) << std::setw(6) << detector.position().z()
358  << ", phi: " << std::setprecision(3) << std::setw(6) << detector.position().phi() << ")"
359  << std::endl;
360  }
361  if (inside > 1) {
362  index = 0;
363  std::cerr << "TrackingMaterialAnalyser::findLayer(...): ERROR: detector belongs to " << inside << "DetLayers" << std::endl;
364  std::cerr << "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() << ")"
368  << std::endl;
369  }
370 
371  return index;
372 }
373 
374 //-------------------------------------------------------------------------
375 // define as a plugin
void plotSegmentUnassigned(const MaterialAccountingStep &step)
T getParameter(std::string const &) const
int i
Definition: DBlmapReader.cc:9
dictionary parameters
Definition: Parameters.py:2
static const TGPicture * info(bool iBackgroundIsBlack)
T perp() const
Definition: PV3DBase.h:72
double averageRadiationLengths(void) const
return the average normalized number of radiation lengths
std::vector< MaterialAccountingDetector > m_detectors
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::EventIDconst &, edm::Timestampconst & > We also list in braces which AR_WATCH_USING_METHOD_ is used for those or
Definition: Activities.doc:12
double sigmaLength(void) const
return the sigma of the normalized layer thickness
#define DEFINE_FWK_MODULE(type)
Definition: MakerMacros.h:17
double sigmaRadiationLengths(void) const
return the sigma of the normalized number of radiation lengths
std::vector< MaterialAccountingStep > m_steps
Geom::Phi< T > phi() const
Definition: PV3DBase.h:69
double length(void) const
double sigmaEnergyLoss(void) const
return the sigma of the normalized energy loss density factor for Bethe-Bloch
#define NULL
Definition: scimark2.h:8
string format
Some error handling for the usage.
MaterialAccountingStep m_total
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 saveXml(const char *name)
void saveParameters(const char *name)
int findLayer(const MaterialAccountingDetector &detector)
double averageEnergyLoss(void) const
return the average normalized energy loss density factor for Bethe-Bloch
T z() const
Definition: PV3DBase.h:64
#define end
Definition: vmac.h:37
How EventSelector::AcceptEvent() decides whether to accept an event for output otherwise it is excluding the probing of A single or multiple positive and the trigger will pass if any such matching triggers are PASS or EXCEPTION[A criterion thatmatches no triggers at all is detected and causes a throw.] A single negative with an expectation of appropriate bit checking in the decision and the trigger will pass if any such matching triggers are FAIL or EXCEPTION A wildcarded negative criterion that matches more than one trigger in the trigger but the state exists so we define the behavior If all triggers are the negative crieriion will lead to accepting the event(this again matches the behavior of"!*"before the partial wildcard feature was incorporated).The per-event"cost"of each negative criterion with multiple relevant triggers is about the same as!*was in the past
const std::string & name(void) const
get the layer name
std::vector< std::string > m_groupNames
TrackingMaterialPlotter * m_plotter
std::vector< MaterialAccountingGroup * > m_groups
const T & get() const
Definition: EventSetup.h:55
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:30
TrackingMaterialAnalyser(const edm::ParameterSet &)
void plotSegmentInLayer(const MaterialAccountingStep &step, int layer)
tuple cout
Definition: gather_cfg.py:121
void analyze(const edm::Event &, const edm::EventSetup &)
void setup(std::vector< TH2F > &depth, std::string name, std::string units="")