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