GeometryInterface

InterestingQuantities

Macros

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
#ifndef SiPixel_GeometryInterface_h
#define SiPixel_GeometryInterface_h
// -*- C++ -*-
//
// Package:    SiPixelPhase1Common
// Class:      GeometryInterface
//
// The histogram manager uses this class to gather information about a sample.
// All geometry dependence goes here.
//
// Original Author: Marcel Schneider
//

#include "DataFormats/DetId/interface/DetId.h"
#include "FWCore/ParameterSet/interface/ParameterSet.h"
#include "FWCore/Framework/interface/ConsumesCollector.h"
#include "FWCore/Framework/interface/Event.h"
#include "FWCore/MessageLogger/interface/MessageLogger.h"

#include "FWCore/Utilities/interface/ESGetToken.h"
#include "FWCore/Utilities/interface/Transition.h"
#include "CondFormats/SiPixelObjects/interface/SiPixelFedCablingMap.h"
#include "CondFormats/DataRecord/interface/SiPixelFedCablingMapRcd.h"
#include "Geometry/TrackerGeometryBuilder/interface/TrackerGeometry.h"
#include "Geometry/Records/interface/TrackerDigiGeometryRecord.h"
#include "DataFormats/TrackerCommon/interface/TrackerTopology.h"
#include "Geometry/Records/interface/TrackerTopologyRcd.h"

#include <functional>
#include <map>
#include <string>
#include <array>

class GeometryInterface {
public:
  // an ID is produced by interning a string name.
  typedef int ID;
  // A column could have multiple IDs if it is a or-form.
  // Not used atm, makes many things much easier.
  typedef ID Column;
  typedef double Value;
  static const Value UNDEFINED;

  // Essentially a map backed by a vector (for the small counts here
  // this should always be faster). Most ops turned out to be not needed.
  typedef std::vector<std::pair<Column, Value>> Values;

  GeometryInterface(const edm::ParameterSet&,
                    edm::ConsumesCollector&&,
                    edm::Transition transition = edm::Transition::BeginRun);

  bool loaded() { return is_loaded; };

  // The hard work happens here.
  void load(edm::EventSetup const& iSetup);

  struct InterestingQuantities {
    // in this order the struct should fit 2 64bit words and is cheap to copy.
    const edm::Event* sourceEvent = nullptr;
    DetId sourceModule;
    int16_t col = 0;
    int16_t row = 0;
  };

  // This has to be fast, _should_ not malloc.
  void extractColumns(std::vector<Column> const& names, InterestingQuantities const& iq, Values& out) {
    out.clear();
    for (Column const& col : names) {
      auto val = extract(col, iq);
      out.push_back(val);
    }
  }

  // the pair return value is historical; it is only really needed with or-columns.
  // But it is cleaner to carry it around.
  std::pair<Column, Value> extract(Column const& col, InterestingQuantities const& iq) {
    assert(col != 0 || !"Extracting invalid column.");
    ID id = col;
    assert(ID(extractors.size()) > id || !"extractors vector too small!");
    auto& ex = extractors[id];
    if (!ex) {  // we have never heard about this. This is a typo for sure.
      edm::LogError("GeometryInterface") << "Undefined column used: " << unintern(id) << ". Check your spelling.\n";
    } else {
      auto val = ex(iq);
      if (val != UNDEFINED) {
        return std::make_pair(Column{id}, val);
      }
    }
    return std::make_pair(col, UNDEFINED);
  }

  Value extract(ID id, DetId did, edm::Event* ev = nullptr, int16_t col = 0, int16_t row = 0) {
    InterestingQuantities iq = {ev, did, col, row};
    return extractors[id](iq);
  }

  // TODO: for Phase0 (and maybe also Phase2) this should include the 4 corners
  // of each ROC (or the *correct* corners of the respective modules).
  std::vector<InterestingQuantities> const& allModules() { return all_modules; }

  Value maxValue(ID id) { return max_value[id]; };
  Value minValue(ID id) { return min_value[id]; };
  Value binWidth(ID id) { return bin_width[id]; };

  // turn string into an ID, adding it if needed.
  ID intern(std::string const& id) {
    auto it = ids.find(id);
    if (it == ids.end()) {
      ids[id] = ++max_id;
      extractors.resize(max_id + 1);
    }
    return ids[id];
  };

  // turn an ID back into a string. Only for pretty output (including histo
  // labels), so it can be slow (though intern() does not have to be fast
  // either).
  std::string unintern(ID id) {
    for (auto& e : ids)
      if (e.second == id)
        return e.first;
    return "INVALID";
  }

  std::string pretty(Column col) { return unintern(col); }

  std::string formatValue(Column, Value);

private:
  void loadFromTopology(const TrackerGeometry&, const TrackerTopology&, const edm::ParameterSet&);
  void loadFromSiPixelCoordinates(const TrackerGeometry&,
                                  const TrackerTopology&,
                                  const SiPixelFedCablingMap&,
                                  const edm::ParameterSet&);
  void loadTimebased(const edm::ParameterSet& iConfig);
  void loadModuleLevel(const edm::ParameterSet& iConfig);
  void loadFEDCabling(const SiPixelFedCablingMap*);

  const edm::ParameterSet iConfig;

  edm::ESGetToken<TrackerGeometry, TrackerDigiGeometryRecord> trackerGeometryToken_;
  edm::ESGetToken<TrackerTopology, TrackerTopologyRcd> trackerTopologyToken_;
  // When converting this module to use esConsumes I preserved the previous behavior.
  // In one place a configurable label is allowed when getting SiPixelFedCablingMap
  // and in another place it always assumes an empty label. I am not sure if this is
  // actually correct (seems strange). Maybe it does not matter as in all the configurations
  // I could find in the repository the parameter was an empty string... An expert who
  // understands this might want to fix this or eliminate this comment if the behavior is
  // correct.
  edm::ESGetToken<SiPixelFedCablingMap, SiPixelFedCablingMapRcd> siPixelFedCablingMapToken_;
  edm::ESGetToken<SiPixelFedCablingMap, SiPixelFedCablingMapRcd> labeledSiPixelFedCablingMapToken_;
  std::string cablingMapLabel_;

  bool is_loaded = false;

  // This holds closures that compute the column values in step1.
  // can be a Vector since ids are dense.
  std::vector<std::function<Value(InterestingQuantities const& iq)>> extractors;
  // quantity range if it is known. Can be UNDEFINED, in this case booking will
  // determine the range. Map for ease of use.
  std::map<ID, Value> max_value;
  std::map<ID, Value> min_value;
  std::map<ID, Value> bin_width;

  // cache of pre-formatted values. Can be pre-populated while loading
  // (used for Pixel*Name)
  std::map<std::pair<Column, Value>, std::string> format_value;

  void addExtractor(ID id,
                    std::function<Value(InterestingQuantities const& iq)> func,
                    Value min = UNDEFINED,
                    Value max = UNDEFINED,
                    Value binwidth = 1) {
    max_value[id] = max;
    min_value[id] = min;
    bin_width[id] = binwidth;
    extractors[id] = func;
  }

  std::vector<InterestingQuantities> all_modules;

  // interning table. Maps string IDs to a dense set of integer IDs
  std::map<std::string, ID> ids{std::make_pair(std::string("INVALID"), ID(0))};
  ID max_id = 0;
};

#endif