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 #include <boost/filesystem.hpp>
12 
18 
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  if (boost::filesystem::is_directory(name))
110  boost::filesystem::remove_all(name);
111  boost::filesystem::create_directory(name);
112  for (unsigned int i = 0; i < m_groups.size(); ++i) {
113  MaterialAccountingGroup & layer = *(m_groups[i]);
114  layer.savePlots(name);
115  }
116 }
117 
118 //-------------------------------------------------------------------------
119 // FIXME we should save the parameters/xml/plots to a different file per IOV
121 {
122  if (m_saveParameters)
123  saveParameters("parameters");
124 
125  if (m_saveXml)
126  saveXml("parameters.xml");
127 
129  saveLayerPlots("layers");
130 
131  if (m_saveSummaryPlot and m_plotter) {
132  m_plotter->normalize();
133  m_plotter->draw();
134  }
135 }
136 
137 //-------------------------------------------------------------------------
139 {
140  save();
141 }
142 
143 //-------------------------------------------------------------------------
145 {
146  if (m_geometryWatcher.check(setup)) {
148  setup.get<IdealGeometryRecord>().get( hDDD );
149 
150  if (m_groups.empty()) {
151  // initialise the layers for the first time
152  m_groups.resize( m_groupNames.size(), nullptr );
153  } else {
154  // the geometry has changed: save the current parameters/xml/plots and re-initialise the layers
155  save();
156  for (unsigned int i = 0; i < m_groups.size(); ++i)
157  delete m_groups[i];
158  if (m_plotter)
159  m_plotter->reset();
160  }
161 
162  for (unsigned int i = 0; i < m_groups.size(); ++i)
163  m_groups[i] = new MaterialAccountingGroup( m_groupNames[i], * hDDD);
164 
165  // INFO
166  std::cout << "TrackingMaterialAnalyser: List of the tracker groups: " << std::endl;
167  for (unsigned int i = 0; i < m_groups.size(); ++i)
168  std::cout << '\t' << m_groups[i]->info() << std::endl;
169  std::cout << std::endl;
170  }
171 
173  event.getByLabel(m_material, h_tracks);
174 
175  for (std::vector<MaterialAccountingTrack>::const_iterator t = h_tracks->begin(), end = h_tracks->end(); t != end; ++t) {
176  MaterialAccountingTrack track(*t);
177  split( track );
178  }
179 }
180 
181 //-------------------------------------------------------------------------
182 // split a track in segments, each associated to a sensitive detector in a DetLayer;
183 // then, associate each step to one segment, splitting the steps across the segment boundaries
184 //
185 // Nota Bene: this implementation assumes that the steps stored along each track are consecutive and adjacent,
186 // and that no step can span across 3 layers, since all steps should split at layer boundaries
187 
189 {
190  // group sensitive detectors by their DetLayer
191  std::vector<int> group( track.m_detectors.size() );
192  for (unsigned int i = 0; i < track.m_detectors.size(); ++i)
193  group[i] = findLayer( track.m_detectors[i] );
194 
195  unsigned int detectors = track.m_detectors.size();
196  if (detectors == 0) {
197  // the track doesn't cross any active detector:
198  // keep al material as unassigned
199  if (m_plotter)
200  for (unsigned int i = 1; i < track.m_steps.size(); ++i)
202  } else {
203  const double TOLERANCE = 0.0001; // 1 um tolerance
204  std::vector<double> limits(detectors + 2);
205 
206  // define the trivial limits
208  limits[0] = track.m_detectors[0].m_curvilinearIn - TOLERANCE;
209  else
210  limits[0] = - TOLERANCE;
212  limits[detectors] = track.m_detectors[detectors-1].m_curvilinearOut + TOLERANCE;
213  else
214  limits[detectors] = track.m_total.length() + TOLERANCE;
215  limits[detectors+1] = INFINITY; // this is probably no more needed, but doesn't harm...
216 
217  // pick the algorithm to define the non-trivial limits
218  switch (m_splitMode) {
219  // assign each segment to the the nearest layer
220  // e.g. the material between pixel barrel 3 and TIB 1 will be split among the two
221  case NEAREST_LAYER:
222  for (unsigned int i = 1; i < detectors; ++i)
223  limits[i] = (track.m_detectors[i-1].m_curvilinearOut + track.m_detectors[i].m_curvilinearIn) / 2.;
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.m_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.m_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  //for (unsigned int i = 0; i < detectors; ++i)
247  // std::cout << "MaterialAccountingTrack::split(): detector region boundaries: [" << limits[i] << ", " << limits[i+1] << "] along track" << std::endl;
248 
249  double begin = 0.; // begginning of step, along the track
250  double end = 0.; // end of step, along the track
251  unsigned int i = 1; // step conter
252 
253  // skip the material before the first layer
254  //std::cout << "before first layer, skipping" << std::endl;
255  while (end < limits[0]) {
256  const MaterialAccountingStep & step = track.m_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  //std::cout << '.';
265  }
266  //std::cout << std::endl;
267 
268  // optionally split a step across the first layer boundary
269  //std::cout << "first layer (0): " << limits[0] << ".." << limits[1] << std::endl;
270  if (begin < limits[0] and end > limits[0]) {
271  const MaterialAccountingStep & step = track.m_steps[i++];
272  end = begin + step.length();
273 
274  double fraction = (limits[0] - begin) / (end - begin);
275  std::pair<MaterialAccountingStep, MaterialAccountingStep> parts = step.split(fraction);
276 
277  //std::cout << '!' << std::endl;
278  track.m_detectors[0].account( parts.second, limits[1], end );
279 
280  if (m_plotter) {
281  // step partially before first layer, keep first part as unassocated
282  m_plotter->plotSegmentUnassigned( parts.first );
283 
284  // associate second part to first layer
285  m_plotter->plotSegmentInLayer( parts.second, group[0] );
286  }
287  begin = end;
288  }
289 
290  unsigned int index = 0; // which detector
291  while (i < track.m_steps.size()) {
292  const MaterialAccountingStep & step = track.m_steps[i++];
293 
294  end = begin + step.length();
295 
296  if (begin > limits[detectors]) {
297  // segment after last layer and skipping requested in configuation
298  if (m_plotter)
300  begin = end;
301  continue;
302  }
303 
304  // from here onwards we should be in the accountable region, either completely in a single layer:
305  // limits[index] <= begin < end <= limits[index+1]
306  // or possibly split between 2 layers
307  // limits[index] < begin < limits[index+1] < end < limits[index+2]
308  if (begin < limits[index] or end > limits[index+2]) {
309  // sanity check
310  std::cerr << "MaterialAccountingTrack::split(): ERROR: internal logic error, expected " << limits[index] << " < " << begin << " < " << limits[index+1] << std::endl;
311  break;
312  }
313 
314  //std::cout << '.';
315  if (limits[index] <= begin and end <= limits[index+1]) {
316  // step completely inside current detector range
317  track.m_detectors[index].account( step, begin, end );
318  if (m_plotter)
319  m_plotter->plotSegmentInLayer( step, group[index] );
320  } else {
321  // step shared beteewn two detectors, transition at limits[index+1]
322  double fraction = (limits[index+1] - begin) / (end - begin);
323  std::pair<MaterialAccountingStep, MaterialAccountingStep> parts = step.split(fraction);
324 
325  if (m_plotter) {
326  if (index > 0)
327  m_plotter->plotSegmentInLayer( parts.first, group[index] );
328  else
329  // track outside acceptance, keep as unassocated
330  m_plotter->plotSegmentUnassigned( parts.first );
331 
332  if (index+1 < detectors)
333  m_plotter->plotSegmentInLayer( parts.second, group[index+1] );
334  else
335  // track outside acceptance, keep as unassocated
336  m_plotter->plotSegmentUnassigned( parts.second );
337  }
338 
339  track.m_detectors[index].account( parts.first, begin, limits[index+1] );
340  ++index; // next layer
341  //std::cout << '!' << std::endl;
342  //std::cout << "next layer (" << index << "): " << limits[index] << ".." << limits[index+1] << std::endl;
343  if (index < detectors)
344  track.m_detectors[index].account( parts.second, limits[index+1], end );
345  }
346  begin = end;
347  }
348 
349  }
350  //std::cout << std::endl;
351 
352  // add the material from each detector to its layer (if there is one and only one)
353  for (unsigned int i = 0; i < track.m_detectors.size(); ++i)
354  if (group[i] != 0)
355  m_groups[group[i]-1]->addDetector( track.m_detectors[i] );
356 
357  // end of track: commit internal buffers and reset the m_groups internal state for a new track
358  for (unsigned int i = 0; i < m_groups.size(); ++i)
359  m_groups[i]->endOfTrack();
360 }
361 
362 //-------------------------------------------------------------------------
363 // 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)
365 {
366  int index = 0;
367  size_t inside = 0;
368  for (size_t i = 0; i < m_groups.size(); ++i)
369  if (m_groups[i]->inside(detector)) {
370  ++inside;
371  index = i+1;
372  }
373  if (inside == 0) {
374  index = 0;
375  std::cerr << "TrackingMaterialAnalyser::findLayer(...): ERROR: detector does not belong to any DetLayer" << std::endl;
376  std::cerr << "TrackingMaterialAnalyser::findLayer(...): detector position: " << std::fixed
377  << " (r: " << std::setprecision(1) << std::setw(5) << detector.position().perp()
378  << ", z: " << std::setprecision(1) << std::setw(6) << detector.position().z()
379  << ", phi: " << std::setprecision(3) << std::setw(6) << detector.position().phi() << ")"
380  << std::endl;
381  }
382  if (inside > 1) {
383  index = 0;
384  std::cerr << "TrackingMaterialAnalyser::findLayer(...): ERROR: detector belongs to " << inside << "DetLayers" << std::endl;
385  std::cerr << "TrackingMaterialAnalyser::findLayer(...): detector position: " << std::fixed
386  << " (r: " << std::setprecision(1) << std::setw(5) << detector.position().perp()
387  << ", z: " << std::setprecision(1) << std::setw(6) << detector.position().z()
388  << ", phi: " << std::setprecision(3) << std::setw(6) << detector.position().phi() << ")"
389  << std::endl;
390  }
391 
392  return index;
393 }
394 
395 //-------------------------------------------------------------------------
396 // 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
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
edm::ESWatcher< IdealGeometryRecord > m_geometryWatcher
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
#define nullptr
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
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)
void saveLayerPlots(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:38
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
void savePlots(const char *directory)
save the plots
std::vector< MaterialAccountingGroup * > m_groups
const T & get() const
Definition: EventSetup.h:55
std::pair< MaterialAccountingStep, MaterialAccountingStep > split(double fraction) const
split the step (0..1) in (0..f) + (f..1) using linear interpolation
bool check(const edm::EventSetup &iSetup)
Definition: ESWatcher.h:59
const GlobalPoint & position() const
#define begin
Definition: vmac.h:31
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="")