DetectorType

PPSTimingCalibrationESSource

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
/****************************************************************************
 *
 * This is a part of CTPPS offline software.
 * Authors:
 *   Edoardo Bossini
 *   Filip Dej
 *   Laurent Forthomme
 *
 * NOTE:
 *   Given implementation handles calibration files in JSON format,
 *   which can be generated using dedicated python script.
 *
 ****************************************************************************/

#include "FWCore/Framework/interface/MakerMacros.h"
#include "FWCore/Framework/interface/SourceFactory.h"
#include "FWCore/Framework/interface/ESHandle.h"
#include "FWCore/Framework/interface/ESProducer.h"
#include "FWCore/Framework/interface/EventSetupRecordIntervalFinder.h"
#include "FWCore/Framework/interface/ESProducts.h"

#include "FWCore/ParameterSet/interface/ParameterSet.h"

#include "CondFormats/PPSObjects/interface/PPSTimingCalibration.h"
#include "CondFormats/DataRecord/interface/PPSTimingCalibrationRcd.h"

#include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/ptree.hpp>

namespace pt = boost::property_tree;

//------------------------------------------------------------------------------

class PPSTimingCalibrationESSource : public edm::ESProducer, public edm::EventSetupRecordIntervalFinder {
public:
  PPSTimingCalibrationESSource(const edm::ParameterSet&);

  edm::ESProducts<std::unique_ptr<PPSTimingCalibration> > produce(const PPSTimingCalibrationRcd&);

  static void fillDescriptions(edm::ConfigurationDescriptions&);

private:
  enum struct DetectorType { INVALID = 0, TOTEM_UFSD = 1, PPS_DIAMOND = 2 };

  void setIntervalFor(const edm::eventsetup::EventSetupRecordKey&,
                      const edm::IOVSyncValue&,
                      edm::ValidityInterval&) override;

  /// Extract calibration data from JSON file (TOTEM vertical)
  std::unique_ptr<PPSTimingCalibration> parseTotemUFSDJsonFile() const;
  /// Extract calibration data from JSON file (PPS horizontal diamond)
  std::unique_ptr<PPSTimingCalibration> parsePPSDiamondJsonFile() const;

  const std::string filename_;
  DetectorType subdetector_;
};

//------------------------------------------------------------------------------

PPSTimingCalibrationESSource::PPSTimingCalibrationESSource(const edm::ParameterSet& iConfig)
    : filename_(iConfig.getParameter<edm::FileInPath>("calibrationFile").fullPath()),
      subdetector_((DetectorType)iConfig.getParameter<unsigned int>("subDetector")) {
  setWhatProduced(this);
  findingRecord<PPSTimingCalibrationRcd>();
}

//------------------------------------------------------------------------------

edm::ESProducts<std::unique_ptr<PPSTimingCalibration> > PPSTimingCalibrationESSource::produce(
    const PPSTimingCalibrationRcd&) {
  switch (subdetector_) {
    case DetectorType::TOTEM_UFSD:
      return edm::es::products(parseTotemUFSDJsonFile());
    case DetectorType::PPS_DIAMOND:
      return edm::es::products(parsePPSDiamondJsonFile());
    default:
      throw cms::Exception("PPSTimingCalibrationESSource") << "Subdetector " << (int)subdetector_ << " not recognised!";
  }
}

//------------------------------------------------------------------------------

void PPSTimingCalibrationESSource::setIntervalFor(const edm::eventsetup::EventSetupRecordKey&,
                                                  const edm::IOVSyncValue&,
                                                  edm::ValidityInterval& oValidity) {
  oValidity = edm::ValidityInterval(edm::IOVSyncValue::beginOfTime(), edm::IOVSyncValue::endOfTime());
}

//------------------------------------------------------------------------------

std::unique_ptr<PPSTimingCalibration> PPSTimingCalibrationESSource::parseTotemUFSDJsonFile() const {
  pt::ptree mother_node;
  pt::read_json(filename_, mother_node);

  const std::string formula = mother_node.get<std::string>("formula");
  PPSTimingCalibration::ParametersMap params;
  PPSTimingCalibration::TimingMap time_info;

  for (pt::ptree::value_type& par : mother_node.get_child("parameters")) {
    PPSTimingCalibration::Key key;
    key.db = (int)strtol(par.first.data(), nullptr, 10);

    for (pt::ptree::value_type& board : par.second) {
      key.sampic = board.second.get<int>("sampic");
      key.channel = board.second.get<int>("channel");
      double timeOffset = board.second.get<double>("time_offset");
      double timePrecision = board.second.get<double>("time_precision");
      key.cell = -1;
      time_info[key] = {timeOffset, timePrecision};

      int cell_ct = 0;
      for (pt::ptree::value_type& cell : board.second.get_child("cells")) {
        std::vector<double> values;
        key.cell = cell_ct;

        for (pt::ptree::value_type& param : cell.second)
          values.emplace_back(std::stod(param.second.data(), nullptr));
        params[key] = values;
        cell_ct++;
      }
    }
  }
  return std::make_unique<PPSTimingCalibration>(formula, params, time_info);
}

std::unique_ptr<PPSTimingCalibration> PPSTimingCalibrationESSource::parsePPSDiamondJsonFile() const {
  pt::ptree mother_node;
  pt::read_json(filename_, mother_node);

  const std::string formula = mother_node.get<std::string>("formula");
  PPSTimingCalibration::ParametersMap params;
  PPSTimingCalibration::TimingMap time_info;

  for (pt::ptree::value_type& par : mother_node.get_child("Parameters.Sectors")) {
    PPSTimingCalibration::Key key;
    key.db = par.second.get<int>("sector");

    for (pt::ptree::value_type& st : par.second.get_child("Stations")) {
      key.sampic = st.second.get<int>("station");

      for (pt::ptree::value_type& pl : st.second.get_child("Planes")) {
        key.channel = pl.second.get<int>("plane");

        for (pt::ptree::value_type& ch : pl.second.get_child("Channels")) {
          key.cell = ch.second.get<int>("channel");
          double timeOffset = ch.second.get<double>("time_offset");
          double timePrecision = ch.second.get<double>("time_precision");
          time_info[key] = {timeOffset, timePrecision};

          std::vector<double> values;
          for (pt::ptree::value_type& param : ch.second.get_child("param"))
            values.emplace_back(std::stod(param.second.data(), nullptr));
          params[key] = values;
        }
      }
    }
  }
  return std::make_unique<PPSTimingCalibration>(formula, params, time_info);
}

void PPSTimingCalibrationESSource::fillDescriptions(edm::ConfigurationDescriptions& descriptions) {
  edm::ParameterSetDescription desc;
  desc.add<edm::FileInPath>("calibrationFile", edm::FileInPath())
      ->setComment("file with SAMPIC calibrations, ADC and INL; if empty or corrupted, no calibration will be applied");
  desc.add<unsigned int>("subDetector", (unsigned int)PPSTimingCalibrationESSource::DetectorType::INVALID)
      ->setComment("type of sub-detector for which the calibrations are provided");

  descriptions.add("ppsTimingCalibrationESSource", desc);
}

DEFINE_FWK_EVENTSETUP_SOURCE(PPSTimingCalibrationESSource);