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 188 189 190 191 192 193 194 195
//
// Original Author:  Alexx Perloff Feb 22, 2017
// $Id: JetCorrectorParameters.cc,v 1.20 2012/03/01 18:24:53 srappocc Exp $
//
// Helper class for JetCorrectorParameters
//
#include "CondFormats/JetMETObjects/interface/JetCorrectorParametersHelper.h"
#include <sstream>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <iterator>

//------------------------------------------------------------------------
//--- JetCorrectorParameters::JetCorrectorParametersHelper initializer ---
//--- initializes the mBinMap for quick lookup of mRecords ---------------
//------------------------------------------------------------------------
void JetCorrectorParametersHelper::initTransientMaps() {
  mIndexMap.clear();
  mMap.clear();
  mBinBoundaries.clear();
  mBinBoundaries.assign(JetCorrectorParameters::MAX_SIZE_DIMENSIONALITY, std::vector<float>(0, 0));
}
void JetCorrectorParametersHelper::init(const JetCorrectorParameters::Definitions& mDefinitionsLocal,
                                        const std::vector<JetCorrectorParameters::Record>& mRecordsLocal) {
  SIZE = mDefinitionsLocal.nBinVar();
  if (SIZE > JetCorrectorParameters::MAX_SIZE_DIMENSIONALITY) {
    std::stringstream sserr;
    sserr << "The number of binned variables requested (" << SIZE << ") is greater than the number allowed ("
          << JetCorrectorParameters::MAX_SIZE_DIMENSIONALITY << ")";
    handleError("JetCorrectorParametersHelper", sserr.str());
  }

  initTransientMaps();
  size_t start = 0, end = 0;
  size_t nRec = mRecordsLocal.size();
  size_t indexMapSize = 0, tmpIndexMapSize = 0;
  for (unsigned i = 0; i < nRec; ++i) {
    for (unsigned j = 0; j < SIZE; j++) {
      if (j < SIZE - 1 && std::find(mBinBoundaries[j].begin(), mBinBoundaries[j].end(), mRecordsLocal[i].xMin(j)) ==
                              mBinBoundaries[j].end())
        mBinBoundaries[j].push_back(mRecordsLocal[i].xMin(j));
      else if (j == SIZE - 1) {
        if (i == 0)
          mBinBoundaries[j].reserve(mRecordsLocal.size());

        mBinBoundaries[j].push_back(mRecordsLocal[i].xMin(j));

        if (SIZE > 1 && (i == nRec - 1 || mRecordsLocal[i].xMin(j - 1) != mRecordsLocal[i + 1].xMin(j - 1))) {
          end = i;
          //mMap.emplace(gen_tuple<SIZE-1>([&](size_t k){return mRecordsLocal[i].xMin(k);}),std::make_pair(start,end));
          mMap.emplace(gen_tuple<JetCorrectorParameters::MAX_SIZE_DIMENSIONALITY - 1>(
                           [&](size_t k) { return (k < SIZE - 1) ? mRecordsLocal[i].xMin(k) : -9999; }),
                       std::make_pair(start, end));
          start = i + 1;
        }
      }
    }
    indexMapSize = mIndexMap.size();
    tuple_type tmpTuple = gen_tuple<JetCorrectorParameters::MAX_SIZE_DIMENSIONALITY>(
        [&](size_t k) { return (k < SIZE) ? mRecordsLocal[i].xMin(k) : -9999; });
    mIndexMap.emplace(tmpTuple, i);
    tmpIndexMapSize = mIndexMap.size();
    if (indexMapSize == tmpIndexMapSize) {
      size_t existing_index = mIndexMap.find(tmpTuple)->second;
      std::stringstream sserr;
      sserr << "Duplicate binning in record found (existing index,current index)=(" << existing_index << "," << i << ")"
            << std::endl
            << "\tBins(lower bounds)=" << tmpTuple;
      handleError("JetCorrectorParametersHelper", sserr.str());
    }
  }
  if (mBinBoundaries[SIZE - 1].size() != nRec) {
    std::stringstream sserr;
    sserr << "Did not find all bin boundaries for dimension " << SIZE - 1 << "!!!" << std::endl
          << "Found " << mBinBoundaries[SIZE - 1].size() << " out of " << nRec << " records";
    handleError("JetCorrectorParametersHelper", sserr.str());
  }
  indexMapSize = mIndexMap.size();
  if (indexMapSize != nRec) {
    handleError("JetCorrectorParametersHelper",
                "The mapping of bin lower bounds to indices does not contain all possible entries!!!");
  }
  // This function checks that all of the middle binned parameters (not the first or last) contain the same range of bins.
  // If not an exception will be thrown as the mapping will work only if all bins but the last are uniform.
  if (SIZE > 2)
    checkMiddleBinUniformity(mRecordsLocal);
}

void JetCorrectorParametersHelper::checkMiddleBinUniformity(
    const std::vector<JetCorrectorParameters::Record>& mRecords) const {
  unsigned N = SIZE - 2;
  size_t nRec = mRecords.size();
  std::vector<int> fN(N, -1);
  //The order of looping (records or dimensions) does not matter because you have to go through all of them once anyway
  //Loop over each binned dimension that isn't the first or the last
  for (unsigned idim = 1; idim <= N; idim++) {
    int nBoundaryPassed = 0;
    if (fN[idim - 1] == -1)
      fN[idim - 1] = mBinBoundaries[idim].size();
    //Loop over the mRecords vector
    for (unsigned iRecord = 0; iRecord < nRec; iRecord++) {
      if (mRecords[iRecord].xMin(idim) != mBinBoundaries[idim][nBoundaryPassed % fN[idim - 1]]) {
        throw cms::Exception("MissingRecord")
            << "found a missing record in binned dimension " << idim << " after record " << iRecord << std::endl
            << "\tthe bin lower bound should have been " << mBinBoundaries[idim][nBoundaryPassed % fN[idim - 1]]
            << ", but was instead " << mRecords[iRecord].xMin(idim) << std::endl
            << "\tall binned dimensions, besides the last one, must have uniform binning." << std::endl
            << mRecords[iRecord - 1] << std::endl
            << mRecords[iRecord] << std::endl;
      } else if ((iRecord == nRec - 1 || mRecords[iRecord].xMin(idim) != mRecords[iRecord + 1].xMin(idim))) {
        nBoundaryPassed++;
      } else {
        continue;
      }
    }
  }
}

//------------------------------------------------------------------------
//--- JetCorrectorParameters::JetCorrectorParametersHelper sanity checks -
//--- checks that some conditions are met before finding the bin index ---
//------------------------------------------------------------------------
void JetCorrectorParametersHelper::binIndexChecks(unsigned N, const std::vector<float>& fX) const {
  if (N != fX.size()) {
    std::stringstream sserr;
    sserr << "The number of binned variables, " << N << ", doesn't correspond to the number requested, " << fX.size();
    handleError("JetCorrectorParametersHelper", sserr.str());
  }
}
bool JetCorrectorParametersHelper::binBoundChecks(unsigned dim,
                                                  const float& value,
                                                  const float& min,
                                                  const float& max) const {
  if (value < min || value >= max)
    return false;
  else
    return true;
}
//------------------------------------------------------------------------
//--- JetCorrectorParameters::JetCorrectorParametersHelper binIndexN -----
//--- returns the index of the record defined by fX (non-linear search) --
//------------------------------------------------------------------------
int JetCorrectorParametersHelper::binIndexN(const std::vector<float>& fX,
                                            const std::vector<JetCorrectorParameters::Record>& mRecords) const {
  unsigned Nm1 = SIZE - 1;
  binIndexChecks(SIZE, fX);

  //Create a container for the indices
  std::vector<float> fN(SIZE, -1);
  std::vector<float>::const_iterator tmpIt;

  // make sure that fX are within the first and last boundaries of mBinBoundaries (other than last dimension)
  for (unsigned idim = 0; idim == 0 || idim < fX.size() - 1; idim++) {
    if (!binBoundChecks(idim, fX[idim], *mBinBoundaries[idim].begin(), mRecords[size() - 1].xMax(idim)))
      return -1;
    tmpIt = std::lower_bound(mBinBoundaries[idim].begin(), mBinBoundaries[idim].end(), fX[idim]);
    // lower_bound finds the entry with the next highest value to fX[0]
    // so unless the two values are equal, you want the next lowest bin boundary
    if (tmpIt == mBinBoundaries[idim].end())
      tmpIt = mBinBoundaries[idim].begin() + mBinBoundaries[idim].size() - 1;
    else if (*tmpIt != fX[idim])
      tmpIt -= 1;
    fN[idim] = *tmpIt;
  }

  //find the index bounds for the possible values of the last dimension
  std::pair<size_t, size_t> indexBounds;
  if (SIZE > 1) {
    tuple_type_Nm1 to_find_Nm1 = gen_tuple<JetCorrectorParameters::MAX_SIZE_DIMENSIONALITY - 1>(
        [&](size_t i) { return (i < Nm1) ? fN[i] : -9999; });
    if (mMap.find(to_find_Nm1) != mMap.end())
      indexBounds = mMap.at(to_find_Nm1);
    else {
      std::stringstream sserr;
      sserr << "couldn't find the index boundaries for dimension " << Nm1 << std::endl
            << "looking for last bin with N-1 values of " << to_find_Nm1 << std::endl;
      handleError("JetCorrectorParametersHelper", sserr.str());
      return -1;
    }

    //Check that the requested value is within the bin boundaries for the last dimension
    if (!binBoundChecks(Nm1, fX[Nm1], mRecords[indexBounds.first].xMin(Nm1), mRecords[indexBounds.second].xMax(Nm1)))
      return -1;
    tmpIt = std::lower_bound(
        mBinBoundaries[Nm1].begin() + indexBounds.first, mBinBoundaries[Nm1].begin() + indexBounds.second, fX[Nm1]);
    if (*tmpIt != fX[Nm1] && fX[Nm1] < *(mBinBoundaries[Nm1].begin() + indexBounds.second))
      tmpIt -= 1;
    fN[Nm1] = *tmpIt;
  }

  tuple_type to_find =
      gen_tuple<JetCorrectorParameters::MAX_SIZE_DIMENSIONALITY>([&](size_t i) { return (i < SIZE) ? fN[i] : -9999; });
  return (mIndexMap.find(to_find) != mIndexMap.end()) ? mIndexMap.at(to_find) : -1;
}