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 {
140  setup.get<IdealGeometryRecord>().get( hDDD );
141 
142  m_groups.reserve( m_groupNames.size() );
143  // Initialize m_groups iff it has size equal to zero, so that we are
144  // sure it will never be repopulated with the same entries over and
145  // over again in the eventloop, at each call of the analyze method.
146  if (m_groups.size() == 0) {
147  for (unsigned int i = 0; i < m_groupNames.size(); ++i)
148  m_groups.push_back( new MaterialAccountingGroup( m_groupNames[i], * hDDD) );
149 
150  LogDebug("TrackingMaterialAnalyser")
151  << "TrackingMaterialAnalyser: List of the tracker groups: " << std::endl;
152  for (unsigned int i = 0; i < m_groups.size(); ++i)
153  LogDebug("TrackingMaterialAnalyser")
154  << "TrackingMaterialAnalyser:\t" << m_groups[i]->info() << std::endl;
155  }
157  event.getByToken(m_materialToken, h_tracks);
158 
159  for (std::vector<MaterialAccountingTrack>::const_iterator t = h_tracks->begin(), end = h_tracks->end(); t != end; ++t) {
160  MaterialAccountingTrack track(*t);
161  split( track );
162  }
163 }
164 
165 //-------------------------------------------------------------------
166 // split a track in segments, each associated to a sensitive detector
167 // in a DetLayer; then, associate each step to one segment, splitting
168 // the steps across the segment boundaries
169 //
170 // Nota Bene: this implementation assumes that the steps stored along
171 // each track are consecutive and adjacent, and that no step can span
172 // across 3 layers, since all steps should split at layer boundaries
173 
175 {
176  // group sensitive detectors by their DetLayer
177  std::vector<int> group( track.detectors().size() );
178  for (unsigned int i = 0; i < track.detectors().size(); ++i)
179  group[i] = findLayer( track.detectors()[i] );
180 
181  unsigned int detectors = track.detectors().size();
182  if (detectors == 0) {
183  // the track doesn't cross any active detector:
184  // keep al material as unassigned
185  if (m_plotter)
186  for (unsigned int i = 1; i < track.steps().size(); ++i)
187  m_plotter->plotSegmentUnassigned( track.steps()[i] );
188  } else {
189  const double TOLERANCE = 0.0001; // 1 um tolerance
190  std::vector<double> limits(detectors + 2);
191 
192  // define the trivial limits
194  limits[0] = track.detectors()[0].m_curvilinearIn - TOLERANCE;
195  else
196  limits[0] = - TOLERANCE;
198  limits[detectors] = track.detectors()[detectors-1].m_curvilinearOut + TOLERANCE;
199  else
200  limits[detectors] = track.summary().length() + TOLERANCE;
201  limits[detectors+1] = INFINITY; // this is probably no more needed, but doesn't harm...
202 
203  // pick the algorithm to define the non-trivial limits
204  switch (m_splitMode) {
205  // assign each segment to the the nearest layer
206  // e.g. the material between pixel barrel 3 and TIB 1 will be split among the two
207  case NEAREST_LAYER:
208  for (unsigned int i = 1; i < detectors; ++i)
209  limits[i] = (track.detectors()[i-1].m_curvilinearOut + track.detectors()[i].m_curvilinearIn) / 2.;
210  break;
211 
212  // assign each segment to the the inner layer
213  // e.g. all material between pixel barrel 3 and TIB 1 will go into the pixel barrel
214  case INNER_LAYER:
215  for (unsigned int i = 1; i < detectors; ++i)
216  limits[i] = track.detectors()[i].m_curvilinearIn - TOLERANCE;
217  break;
218 
219  // assign each segment to the the outer layer
220  // e.g. all material between pixel barrel 3 and TIB 1 will go into the TIB
221  case OUTER_LAYER:
222  for (unsigned int i = 1; i < detectors; ++i)
223  limits[i] = track.detectors()[i-1].m_curvilinearOut + TOLERANCE;
224  break;
225 
226  case UNDEFINED:
227  default:
228  // throw something
229  throw edm::Exception(edm::errors::LogicError) << "Invalid SplitMode";
230  }
231 
232  //for (unsigned int i = 0; i < detectors; ++i)
233  // std::cout << "MaterialAccountingTrack::split(): detector region boundaries: [" << limits[i] << ", " << limits[i+1] << "] along track" << std::endl;
234 
235  double begin = 0.; // beginning of step, along the track
236  double end = 0.; // end of step, along the track
237  unsigned int i = 1; // step conter
238 
239  // skip the material before the first layer
240  //std::cout << "before first layer, skipping" << std::endl;
241  while (end < limits[0]) {
242  const MaterialAccountingStep & step = track.steps()[i++];
243  end = begin + step.length();
244 
245  // do not account material before the first layer
246  if (m_plotter)
248 
249  begin = end;
250  //std::cout << '.';
251  }
252  //std::cout << std::endl;
253 
254  unsigned int index = 0; // which detector
255  while (i < track.steps().size()) {
256  const MaterialAccountingStep & step = track.steps()[i++];
257 
258  end = begin + step.length();
259 
260  if (begin > limits[detectors]) {
261  // segment after last layer and skipping requested in configuation
262  if (m_plotter)
264  begin = end;
265  continue;
266  }
267 
268  // from here onwards we should be in the accountable region, either completely in a single layer:
269  // limits[index] <= begin < end <= limits[index+1]
270  // or possibly split between 2 layers
271  // limits[index] < begin < limits[index+1] < end < limits[index+2]
272  if (begin < limits[index] or end > limits[index+2]) {
273  // sanity check
274  std::cerr << "MaterialAccountingTrack::split(): ERROR: internal logic error, expected " << limits[index] << " < " << begin << " < " << limits[index+1] << std::endl;
275  break;
276  }
277 
278  //std::cout << '.';
279  if (limits[index] <= begin and end <= limits[index+1]) {
280  // step completely inside current detector range
281  track.detectors()[index].account( step, begin, end );
282  if (m_plotter)
283  m_plotter->plotSegmentInLayer( step, group[index] );
284  } else {
285  // step shared beteewn two detectors, transition at limits[index+1]
286  double fraction = (limits[index+1] - begin) / (end - begin);
287  std::pair<MaterialAccountingStep, MaterialAccountingStep> parts = step.split(fraction);
288 
289  if (m_plotter) {
290  if (index > 0)
291  m_plotter->plotSegmentInLayer( parts.first, group[index] );
292  else
293  // track outside acceptance, keep as unassocated
294  m_plotter->plotSegmentUnassigned( parts.first );
295 
296  if (index+1 < detectors)
297  m_plotter->plotSegmentInLayer( parts.second, group[index+1] );
298  else
299  // track outside acceptance, keep as unassocated
300  m_plotter->plotSegmentUnassigned( parts.second );
301  }
302 
303  track.detectors()[index].account( parts.first, begin, limits[index+1] );
304  ++index; // next layer
305  //std::cout << '!' << std::endl;
306  // std::cout << "next layer (" << index << "): "
307  // << " old det: " << group[index-1] << " new det: " << group[index]
308  // << " " << limits[index] << ".." << limits[index+1] << std::endl;
309  if (index < detectors)
310  track.detectors()[index].account( parts.second, limits[index+1], end );
311  }
312  begin = end;
313  }
314 
315  }
316  //std::cout << std::endl;
317 
318  // add the material from each detector to its layer (if there is one and only one)
319  for (unsigned int i = 0; i < track.detectors().size(); ++i)
320  if (group[i] != 0)
321  m_groups[group[i]-1]->addDetector( track.detectors()[i] );
322 
323  // end of track: commit internal buffers and reset the m_groups internal state for a new track
324  for (unsigned int i = 0; i < m_groups.size(); ++i)
325  m_groups[i]->endOfTrack();
326 }
327 
328 //-------------------------------------------------------------------------
329 // 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)
331 {
332  int index = 0;
333  size_t inside = 0;
334  for (size_t i = 0; i < m_groups.size(); ++i)
335  if (m_groups[i]->inside(detector)) {
336  ++inside;
337  index = i+1;
338  }
339  if (inside == 0) {
340  index = 0;
341  std::cerr << "TrackingMaterialAnalyser::findLayer(...): ERROR: detector does not belong to any DetLayer" << std::endl;
342  std::cerr << "TrackingMaterialAnalyser::findLayer(...): detector position: " << std::fixed
343  << " (r: " << std::setprecision(1) << std::setw(5) << detector.position().perp()
344  << ", z: " << std::setprecision(1) << std::setw(6) << detector.position().z()
345  << ", phi: " << std::setprecision(3) << std::setw(6) << detector.position().phi() << ")"
346  << std::endl;
347  }
348  if (inside > 1) {
349  index = 0;
350  std::cerr << "TrackingMaterialAnalyser::findLayer(...): ERROR: detector belongs to " << inside << " DetLayers" << 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() << ")"
355  << std::endl;
356  }
357 
358  // if (index > 0)
359  // std::cout << m_groups[index-1]->info() << " " << index << std::endl;
360  return index;
361 }
362 
363 //-------------------------------------------------------------------------
364 // define as a plugin
#define LogDebug(id)
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
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
const MaterialAccountingStep & summary() const
void analyze(const edm::Event &, const edm::EventSetup &)
void setup(std::vector< TH2F > &depth, std::string name, std::string units="")