CMS 3D CMS Logo

CMSSW_4_4_3_patch1/src/SimTracker/TrackerMaterialAnalysis/plugins/TrackingMaterialAnalyser.cc

Go to the documentation of this file.
00001 #include <iostream>     // FIXME: switch to MessagLogger & friends
00002 #include <fstream>
00003 #include <sstream>
00004 #include <vector>
00005 #include <string>
00006 #include <stdexcept>
00007 #include <cstring>
00008 #include <cstdlib>
00009 #include <boost/tuple/tuple.hpp>
00010 #include <boost/format.hpp>
00011 
00012 #include "FWCore/Framework/interface/Event.h"
00013 #include "FWCore/Framework/interface/EventSetup.h"
00014 #include "FWCore/Framework/interface/ESTransientHandle.h"
00015 #include "FWCore/ParameterSet/interface/ParameterSet.h"
00016 #include "FWCore/Utilities/interface/EDMException.h"
00017 
00018 #include "DetectorDescription/Core/interface/DDFilteredView.h"
00019 #include "DetectorDescription/Core/interface/DDCompactView.h"
00020 #include "DetectorDescription/Core/interface/DDMaterial.h"
00021 #include "Geometry/Records/interface/IdealGeometryRecord.h"
00022 
00023 #include "SimDataFormats/ValidationFormats/interface/MaterialAccountingStep.h"
00024 #include "SimDataFormats/ValidationFormats/interface/MaterialAccountingTrack.h"
00025 #include "MaterialAccountingGroup.h"
00026 #include "TrackingMaterialAnalyser.h"
00027 #include "TrackingMaterialPlotter.h"
00028 
00029 //-------------------------------------------------------------------------
00030 TrackingMaterialAnalyser::TrackingMaterialAnalyser(const edm::ParameterSet& iPSet)
00031 {
00032   m_material                = iPSet.getParameter<edm::InputTag>("MaterialAccounting");
00033   m_groupNames              = iPSet.getParameter<std::vector<std::string> >("Groups");
00034   const std::string & splitmode = iPSet.getParameter<std::string>("SplitMode");
00035   if (strcasecmp(splitmode.c_str(), "NearestLayer") == 0) {
00036     m_splitMode = NEAREST_LAYER;
00037   } else if (strcasecmp(splitmode.c_str(), "InnerLayer") == 0) {
00038     m_splitMode = INNER_LAYER;
00039   } else if (strcasecmp(splitmode.c_str(), "OuterLayer") == 0) {
00040     m_splitMode = OUTER_LAYER;
00041   } else {
00042     m_splitMode = UNDEFINED;
00043     throw edm::Exception(edm::errors::LogicError) << "Invalid SplitMode \"" << splitmode << "\". Acceptable values are \"NearestLayer\", \"InnerLayer\", \"OuterLayer\".";
00044   }
00045   m_skipAfterLastDetector   = iPSet.getParameter<bool>("SkipAfterLastDetector");
00046   m_skipBeforeFirstDetector = iPSet.getParameter<bool>("SkipBeforeFirstDetector");
00047   m_saveSummaryPlot         = iPSet.getParameter<bool>("SaveSummaryPlot");
00048   m_saveDetailedPlots       = iPSet.getParameter<bool>("SaveDetailedPlots");
00049   m_saveParameters          = iPSet.getParameter<bool>("SaveParameters");
00050   m_saveXml                 = iPSet.getParameter<bool>("SaveXML");
00051   if (m_saveSummaryPlot)
00052     m_plotter               = new TrackingMaterialPlotter( 300., 120., 10 );      // 10x10 points per cm2
00053   else
00054     m_plotter               = NULL;
00055 }
00056 
00057 //-------------------------------------------------------------------------
00058 TrackingMaterialAnalyser::~TrackingMaterialAnalyser(void)
00059 {
00060   if (m_plotter)
00061     delete m_plotter;
00062 }
00063 
00064 //-------------------------------------------------------------------------
00065 void TrackingMaterialAnalyser::saveParameters(const char* name)
00066 {
00067   std::ofstream parameters(name);
00068   std::cout << std::endl;
00069   for (unsigned int i = 0; i < m_groups.size(); ++i) {
00070     MaterialAccountingGroup & layer = *(m_groups[i]);
00071     std::cout << layer.name() << std::endl;
00072     std::cout << boost::format("\tnumber of hits:               %9d") % layer.tracks() << std::endl;
00073     std::cout << boost::format("\tnormalized segment length:    %9.1f ± %9.1f cm")  % layer.averageLength()           % layer.sigmaLength()           << std::endl;
00074     std::cout << boost::format("\tnormalized radiation lengths: %9.3f ± %9.3f")     % layer.averageRadiationLengths() % layer.sigmaRadiationLengths() << std::endl;
00075     std::cout << boost::format("\tnormalized energy loss:       %9.3f ± %9.3f MeV") % layer.averageEnergyLoss()       % layer.sigmaEnergyLoss()       << std::endl;
00076     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")
00077                                 % layer.name()
00078                                 % layer.tracks()
00079                                 % layer.averageLength()               % layer.sigmaLength()
00080                                 % layer.averageRadiationLengths()     % layer.sigmaRadiationLengths()
00081                                 % layer.averageEnergyLoss()           % layer.sigmaEnergyLoss()
00082                << std::endl;
00083   }
00084   std::cout << std::endl;
00085 
00086   parameters.close();
00087 }
00088 
00089 //-------------------------------------------------------------------------
00090 void TrackingMaterialAnalyser::saveXml(const char* name)
00091 {
00092   std::ofstream xml(name);
00093   xml << "<?xml version=\"1.0\" encoding=\"utf-8\"?>" << std::endl;
00094   xml << "<Groups>" << std::endl;
00095   for (unsigned int i = 0; i < m_groups.size(); ++i) {
00096     MaterialAccountingGroup & layer = *(m_groups[i]);
00097     xml << "  <Group name=\"" << layer.name() << "\">\n"
00098         << "    <Parameter name=\"TrackerRadLength\" value=\"" << layer.averageRadiationLengths() << "\"/>\n"
00099         << "    <Parameter name=\"TrackerXi\" value=\"" << layer.averageEnergyLoss() << "\"/>\n"
00100         << "  </Group>\n" 
00101         << std::endl;
00102   }
00103   xml << "</Groups>" << std::endl;
00104 }
00105 
00106 //-------------------------------------------------------------------------
00107 void TrackingMaterialAnalyser::saveLayerPlots()
00108 {
00109   for (unsigned int i = 0; i < m_groups.size(); ++i) {
00110     MaterialAccountingGroup & layer = *(m_groups[i]);
00111     layer.savePlots();
00112   }
00113 }
00114 
00115 //-------------------------------------------------------------------------
00116 void TrackingMaterialAnalyser::endJob(void)
00117 {
00118   if (m_saveParameters)
00119     saveParameters("parameters");
00120 
00121   if (m_saveXml)
00122     saveXml("parameters.xml");
00123 
00124   if (m_saveDetailedPlots)
00125     saveLayerPlots();
00126 
00127   if (m_saveSummaryPlot and m_plotter) {
00128     m_plotter->normalize();
00129     m_plotter->draw();
00130   }
00131 }
00132 
00133 //-------------------------------------------------------------------------
00134 
00135 //-------------------------------------------------------------------------
00136 void TrackingMaterialAnalyser::analyze(const edm::Event& event, const edm::EventSetup& setup)
00137 {
00138   edm::ESTransientHandle<DDCompactView> hDDD;
00139   setup.get<IdealGeometryRecord>().get( hDDD );
00140 
00141   m_groups.reserve( m_groupNames.size() );
00142   for (unsigned int i = 0; i < m_groupNames.size(); ++i)
00143     m_groups.push_back( new MaterialAccountingGroup( m_groupNames[i], * hDDD) ); 
00144 
00145   // INFO
00146   std::cout << "TrackingMaterialAnalyser: List of the tracker groups: " << std::endl;
00147   for (unsigned int i = 0; i < m_groups.size(); ++i)
00148     std::cout << '\t' << m_groups[i]->info() << std::endl;
00149   std::cout << std::endl;
00150 
00151   edm::Handle< std::vector<MaterialAccountingTrack> > h_tracks;
00152   event.getByLabel(m_material, h_tracks);
00153 
00154   for (std::vector<MaterialAccountingTrack>::const_iterator t = h_tracks->begin(), end = h_tracks->end(); t != end; ++t) {
00155     MaterialAccountingTrack track(*t);
00156     split( track );
00157   }
00158 }
00159 
00160 //-------------------------------------------------------------------------
00161 // split a track in segments, each associated to a sensitive detector in a DetLayer;
00162 // then, associate each step to one segment, splitting the steps across the segment boundaries
00163 //
00164 // Nota Bene: this implementation assumes that the steps stored along each track are consecutive and adjacent,
00165 // and that no step can span across 3 layers, since all steps should split at layer boundaries
00166 
00167 void TrackingMaterialAnalyser::split( MaterialAccountingTrack & track )
00168 {
00169   // group sensitive detectors by their DetLayer
00170   std::vector<int> group( track.m_detectors.size() );
00171   for (unsigned int i = 0; i < track.m_detectors.size(); ++i)
00172     group[i] = findLayer( track.m_detectors[i] );
00173 
00174   unsigned int detectors = track.m_detectors.size();
00175   if (detectors == 0) {
00176     // the track doesn't cross any active detector:
00177     // keep al material as unassigned
00178     if (m_plotter)
00179       for (unsigned int i = 1; i < track.m_steps.size(); ++i)
00180         m_plotter->plotSegmentUnassigned( track.m_steps[i] );
00181   } else {
00182     const double TOLERANCE = 0.0001;    // 1 um tolerance
00183     std::vector<double> limits(detectors + 2);
00184 
00185     // define the trivial limits
00186     if (m_skipBeforeFirstDetector)
00187       limits[0] = track.m_detectors[0].m_curvilinearIn - TOLERANCE;
00188     else
00189       limits[0] = - TOLERANCE;
00190     if (m_skipAfterLastDetector)
00191       limits[detectors] = track.m_detectors[detectors-1].m_curvilinearOut + TOLERANCE;
00192     else
00193       limits[detectors] = track.m_total.length() + TOLERANCE;
00194     limits[detectors+1] = INFINITY;     // this is probably no more needed, but doesn't harm...
00195 
00196     // pick the algorithm to define the non-trivial limits
00197     switch (m_splitMode) {
00198       // assign each segment to the the nearest layer
00199       // e.g. the material between pixel barrel 3 and TIB 1 will be split among the two
00200       case NEAREST_LAYER:
00201         for (unsigned int i = 1; i < detectors; ++i)
00202           limits[i] = (track.m_detectors[i-1].m_curvilinearOut + track.m_detectors[i].m_curvilinearIn) / 2.;
00203         break;
00204 
00205       // assign each segment to the the inner layer
00206       // e.g. all material between pixel barrel 3 and TIB 1 will go into the pixel barrel
00207       case INNER_LAYER:
00208         for (unsigned int i = 1; i < detectors; ++i)
00209           limits[i] = track.m_detectors[i].m_curvilinearIn - TOLERANCE;
00210         break;
00211 
00212       // assign each segment to the the outer layer
00213       // e.g. all material between pixel barrel 3 and TIB 1 will go into the TIB
00214       case OUTER_LAYER:
00215         for (unsigned int i = 1; i < detectors; ++i)
00216           limits[i] = track.m_detectors[i-1].m_curvilinearOut + TOLERANCE;
00217         break;
00218 
00219       case UNDEFINED:
00220       default:
00221         // throw something
00222         throw edm::Exception(edm::errors::LogicError) << "Invalid SplitMode";
00223     }
00224 
00225     //for (unsigned int i = 0; i < detectors; ++i)
00226     //  std::cout << "MaterialAccountingTrack::split(): detector region boundaries: [" << limits[i] << ", " << limits[i+1] << "] along track" << std::endl;
00227 
00228     double begin = 0.;          // begginning of step, along the track
00229     double end   = 0.;          // end of step, along the track
00230     unsigned int i = 1;         // step conter
00231 
00232     // skip the material before the first layer
00233     //std::cout << "before first layer, skipping" << std::endl;
00234     while (end < limits[0]) {
00235       const MaterialAccountingStep & step = track.m_steps[i++];
00236       end = begin + step.length();
00237 
00238       // do not account material before the first layer
00239       if (m_plotter)
00240         m_plotter->plotSegmentUnassigned( step );
00241 
00242       begin = end;
00243       //std::cout << '.';
00244     }
00245     //std::cout << std::endl;
00246 
00247     // optionally split a step across the first layer boundary
00248     //std::cout << "first layer (0): " << limits[0] << ".." << limits[1] << std::endl;
00249     if (begin < limits[0] and end > limits[0]) {
00250       const MaterialAccountingStep & step = track.m_steps[i++];
00251       end = begin + step.length();
00252 
00253       double fraction = (limits[0] - begin) / (end - begin);
00254       std::pair<MaterialAccountingStep, MaterialAccountingStep> parts = step.split(fraction);
00255 
00256       //std::cout << '!' << std::endl;
00257       track.m_detectors[0].account( parts.second, limits[1], end );
00258 
00259       if (m_plotter) {
00260         // step partially before first layer, keep first part as unassocated
00261         m_plotter->plotSegmentUnassigned( parts.first );
00262 
00263         // associate second part to first layer
00264         m_plotter->plotSegmentInLayer( parts.second,  group[0] );
00265       }
00266       begin = end;
00267     }
00268 
00269     unsigned int index = 0;     // which detector
00270     while (i < track.m_steps.size()) {
00271       const MaterialAccountingStep & step = track.m_steps[i++];
00272 
00273       end = begin + step.length();
00274 
00275       if (begin > limits[detectors]) {
00276         // segment after last layer and skipping requested in configuation
00277         if (m_plotter)
00278           m_plotter->plotSegmentUnassigned( step );
00279         begin = end;
00280         continue;
00281       }
00282 
00283       // from here onwards we should be in the accountable region, either completely in a single layer:
00284       //   limits[index] <= begin < end <= limits[index+1]
00285       // or possibly split between 2 layers
00286       //   limits[index] < begin < limits[index+1] < end <  limits[index+2]
00287       if (begin < limits[index] or end > limits[index+2]) {
00288         // sanity check
00289         std::cerr << "MaterialAccountingTrack::split(): ERROR: internal logic error, expected " << limits[index] << " < " << begin << " < " << limits[index+1] << std::endl;
00290         break;
00291       }
00292 
00293       //std::cout << '.';
00294       if (limits[index] <= begin and end <= limits[index+1]) {
00295         // step completely inside current detector range
00296         track.m_detectors[index].account( step, begin, end );
00297         if (m_plotter)
00298           m_plotter->plotSegmentInLayer( step, group[index] );
00299       } else {
00300         // step shared beteewn two detectors, transition at limits[index+1]
00301         double fraction = (limits[index+1] - begin) / (end - begin);
00302         std::pair<MaterialAccountingStep, MaterialAccountingStep> parts = step.split(fraction);
00303 
00304         if (m_plotter) {
00305           if (index > 0)
00306             m_plotter->plotSegmentInLayer( parts.first, group[index] );
00307           else
00308             // track outside acceptance, keep as unassocated
00309             m_plotter->plotSegmentUnassigned( parts.first );
00310 
00311           if (index+1 < detectors)
00312             m_plotter->plotSegmentInLayer( parts.second,  group[index+1] );
00313           else
00314             // track outside acceptance, keep as unassocated
00315             m_plotter->plotSegmentUnassigned( parts.second );
00316         }
00317 
00318         track.m_detectors[index].account( parts.first, begin, limits[index+1] );
00319         ++index;          // next layer
00320         //std::cout << '!' << std::endl;
00321         //std::cout << "next layer (" << index << "): " << limits[index] << ".." << limits[index+1] << std::endl;
00322         if (index < detectors)
00323           track.m_detectors[index].account( parts.second, limits[index+1], end );
00324       }
00325       begin = end;
00326     }
00327 
00328   }
00329   //std::cout << std::endl;
00330 
00331   // add the material from each detector to its layer (if there is one and only one)
00332   for (unsigned int i = 0; i < track.m_detectors.size(); ++i)
00333     if (group[i] != 0)
00334       m_groups[group[i]-1]->addDetector( track.m_detectors[i] );
00335 
00336   // end of track: commit internal buffers and reset the m_groups internal state for a new track
00337   for (unsigned int i = 0; i < m_groups.size(); ++i)
00338     m_groups[i]->endOfTrack();
00339 }
00340 
00341 //-------------------------------------------------------------------------
00342 // 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)
00343 int TrackingMaterialAnalyser::findLayer( const MaterialAccountingDetector & detector )
00344 {
00345   int    index  = 0;
00346   size_t inside = 0;
00347   for (size_t i = 0; i < m_groups.size(); ++i)
00348     if (m_groups[i]->inside(detector)) {
00349       ++inside;
00350       index = i+1;
00351     }
00352   if (inside == 0) {
00353     index = 0;
00354     std::cerr << "TrackingMaterialAnalyser::findLayer(...): ERROR: detector does not belong to any DetLayer" << std::endl;
00355     std::cerr << "TrackingMaterialAnalyser::findLayer(...): detector position: " << std::fixed
00356               << " (r: " << std::setprecision(1) << std::setw(5) << detector.position().perp()
00357               << ", z: " << std::setprecision(1) << std::setw(6) << detector.position().z()
00358               << ", phi: " << std::setprecision(3) << std::setw(6) << detector.position().phi() << ")" 
00359               << std::endl;
00360   }
00361   if (inside > 1) {
00362     index = 0;
00363     std::cerr << "TrackingMaterialAnalyser::findLayer(...): ERROR: detector belongs to " << inside << "DetLayers" << std::endl;
00364     std::cerr << "TrackingMaterialAnalyser::findLayer(...): detector position: " << std::fixed
00365               << " (r: " << std::setprecision(1) << std::setw(5) << detector.position().perp()
00366               << ", z: " << std::setprecision(1) << std::setw(6) << detector.position().z()
00367               << ", phi: " << std::setprecision(3) << std::setw(6) << detector.position().phi() << ")" 
00368               << std::endl;
00369   }
00370 
00371   return index;
00372 }
00373 
00374 //-------------------------------------------------------------------------
00375 // define as a plugin
00376 #include "FWCore/PluginManager/interface/ModuleDef.h"
00377 #include "FWCore/Framework/interface/MakerMacros.h"
00378 DEFINE_FWK_MODULE(TrackingMaterialAnalyser);