52  for (
const auto& 
vertex : vertices) {
 
   53    mPrimaryVertices.emplace_back(
vertex); 
 
   54    mTotVertPerIteration[iteration]++;
 
   55    if (!isBeamPositionOverridden) { 
 
   56      const float w = 
vertex.getNContributors();
 
   57      mBeamPos[0] = (mBeamPos[0] * mBeamPosWeight + 
vertex.getX() * 
w) / (mBeamPosWeight + 
w);
 
   58      mBeamPos[1] = (mBeamPos[1] * mBeamPosWeight + 
vertex.getY() * 
w) / (mBeamPosWeight + 
w);
 
   62  mROFramesPV.push_back(mPrimaryVertices.size()); 
 
 
   68  mVerticesMCRecInfo.insert(mVerticesMCRecInfo.end(), labels.begin(), labels.end());
 
 
   74  mVerticesContributorLabels.insert(mVerticesContributorLabels.end(), labels.begin(), labels.end());
 
 
   80  mPrimaryVertices.insert(mPrimaryVertices.begin() + mROFramesPV[rofId], vertices.begin(), vertices.end());
 
   81  for (
int i = rofId + 1; 
i < mROFramesPV.size(); ++
i) {
 
   82    mROFramesPV[
i] += vertices.size();
 
   84  mTotVertPerIteration[iteration] += vertices.size();
 
   90  mVerticesMCRecInfo.insert(mVerticesMCRecInfo.begin() + mROFramesPV[rofId], labels.begin(), labels.end());
 
   98  const auto& pvs = getPrimaryVertices(0, rofId);
 
   99  for (
const auto& pv : pvs) {
 
  100    n += pv.getNContributors();
 
  102  mVerticesContributorLabels.insert(mVerticesContributorLabels.begin() + 
n, labels.begin(), labels.end());
 
  105template <
int nLayers>
 
  107                                        gsl::span<const itsmft::CompClusterExt> 
clusters,
 
  108                                        gsl::span<const unsigned char>::iterator& pattIt,
 
  115  resetROFrameData(rofs.size());
 
  118  for (
size_t iRof{0}; iRof < rofs.size(); ++iRof) {
 
  119    const auto& rof = rofs[iRof];
 
  120    for (
int clusterId{rof.getFirstEntry()}; clusterId < rof.getFirstEntry() + rof.getNEntries(); ++clusterId) {
 
  125      auto pattID = 
c.getPatternID();
 
  145      mClusterSize[clusterId] = std::clamp(
clusterSize, 0u, 255u);
 
  146      auto sensorID = 
c.getSensorID();
 
  152      addTrackingFrameInfoToLayer(
layer, gloXYZ.x(), gloXYZ.y(), gloXYZ.z(), trkXYZ.x(), geom->
getSensorRefAlpha(sensorID),
 
  153                                  std::array<float, 2>{trkXYZ.y(), trkXYZ.z()},
 
  154                                  std::array<float, 3>{sigmaY2, sigmaYZ, sigmaZ2});
 
  156      addClusterToLayer(
layer, gloXYZ.x(), gloXYZ.y(), gloXYZ.z(), mUnsortedClusters[
layer].size());
 
  157      addClusterExternalIndexToLayer(
layer, clusterId);
 
  159    for (
unsigned int iL{0}; iL < mUnsortedClusters.size(); ++iL) {
 
  160      mROFramesClusters[iL][iRof + 1] = mUnsortedClusters[iL].size(); 
 
  164  for (
auto i = 0; 
i < mNTrackletsPerCluster.size(); ++
i) {
 
  165    mNTrackletsPerCluster[
i].resize(mUnsortedClusters[1].
size());
 
  166    mNTrackletsPerClusterSum[
i].resize(mUnsortedClusters[1].
size() + 1); 
 
  169  if (mcLabels != 
nullptr) {
 
  170    mClusterLabels = mcLabels;
 
  176template <
int nLayers>
 
  179  for (
int iLayer{0}; iLayer < nLayers; ++iLayer) {
 
  180    deepVectorClear(mUnsortedClusters[iLayer], getMaybeExternalHostResource());
 
  181    deepVectorClear(mTrackingFrameInfo[iLayer], getMaybeExternalHostResource());
 
 
  193template <
int nLayers>
 
  195                                            gsl::span<const itsmft::CompClusterExt> 
clusters)
 
  200  std::array<int, nLayers> clusterCountPerLayer{};
 
  202    ++clusterCountPerLayer[geom->
getLayer(clus.getSensorID())];
 
  204  for (
int iLayer{0}; iLayer < nLayers; ++iLayer) {
 
  205    mUnsortedClusters[iLayer].reserve(clusterCountPerLayer[iLayer]);
 
  206    mTrackingFrameInfo[iLayer].reserve(clusterCountPerLayer[iLayer]);
 
  207    mClusterExternalIndices[iLayer].reserve(clusterCountPerLayer[iLayer]);
 
  211template <
int nLayers>
 
  212void TimeFrame<nLayers>::prepareClusters(
const TrackingParameters& trkParam, 
const int maxLayers)
 
  214  const int numBins{trkParam.PhiBins * trkParam.ZBins};
 
  215  const int stride{numBins + 1};
 
  216  bounded_vector<ClusterHelper> cHelper(mMemoryPool.get());
 
  217  bounded_vector<int> clsPerBin(numBins, 0, mMemoryPool.get());
 
  218  bounded_vector<int> lutPerBin(numBins, 0, mMemoryPool.get());
 
  219  for (
int rof{0}; rof < mNrof; ++rof) {
 
  220    if ((
int)mMultiplicityCutMask.size() == mNrof && !mMultiplicityCutMask[rof]) {
 
  223    for (
int iLayer{0}, stopLayer = std::min(trkParam.NLayers, maxLayers); iLayer < stopLayer; ++iLayer) {
 
  224      const auto& unsortedClusters{getUnsortedClustersOnLayer(rof, iLayer)};
 
  225      const int clustersNum{
static_cast<int>(unsortedClusters.size())};
 
  226      auto* tableBase = mIndexTables[iLayer].data() + rof * 
stride;
 
  228      cHelper.resize(clustersNum);
 
  230      for (
int iCluster{0}; iCluster < clustersNum; ++iCluster) {
 
  231        const Cluster& 
c = unsortedClusters[iCluster];
 
  232        ClusterHelper& 
h = cHelper[iCluster];
 
  234        const float x = 
c.xCoordinate - mBeamPos[0];
 
  235        const float y = 
c.yCoordinate - mBeamPos[1];
 
  236        const float z = 
c.zCoordinate;
 
  238        float phi = math_utils::computePhi(
x, 
y);
 
  239        int zBin{mIndexTableUtils.getZBinIndex(iLayer, 
z)};
 
  240        if (zBin < 0 || zBin >= trkParam.ZBins) {
 
  241          zBin = std::clamp(zBin, 0, trkParam.ZBins - 1);
 
  242          mBogusClusters[iLayer]++;
 
  244        int bin = mIndexTableUtils.getBinIndex(zBin, mIndexTableUtils.getPhiBinIndex(phi));
 
  246        h.r = math_utils::hypot(
x, 
y);
 
  247        mMinR[iLayer] = o2::gpu::GPUCommonMath::Min(
h.r, mMinR[iLayer]);
 
  248        mMaxR[iLayer] = o2::gpu::GPUCommonMath::Max(
h.r, mMaxR[iLayer]);
 
  250        h.ind = clsPerBin[bin]++;
 
  252      std::exclusive_scan(clsPerBin.begin(), clsPerBin.end(), lutPerBin.begin(), 0);
 
  254      auto clusters2beSorted{getClustersOnLayer(rof, iLayer)};
 
  255      for (
int iCluster{0}; iCluster < clustersNum; ++iCluster) {
 
  256        const ClusterHelper& 
h = cHelper[iCluster];
 
  257        Cluster& 
c = clusters2beSorted[lutPerBin[
h.bin] + 
h.ind];
 
  259        c = unsortedClusters[iCluster];
 
  262        c.indexTableBinIndex = 
h.bin;
 
  264      std::copy_n(lutPerBin.data(), clsPerBin.size(), tableBase);
 
  265      std::fill_n(tableBase + clsPerBin.size(), 
stride - clsPerBin.size(), clustersNum);
 
  267      std::fill(clsPerBin.begin(), clsPerBin.end(), 0);
 
  273template <
int nLayers>
 
  276  if (iteration == 0) {
 
  277    if (maxLayers < trkParam.
NLayers && resetVertices) {
 
  300    mIndexTableUtils.setTrackingParameters(trkParam);
 
  304    for (
unsigned int iLayer{0}; iLayer < std::min((
int)mClusters.size(), maxLayers); ++iLayer) {
 
  313    for (
int iLayer{0}; iLayer < trkParam.
NLayers; ++iLayer) {
 
  315        for (
auto& tfInfo : mTrackingFrameInfo[iLayer]) {
 
  317          tfInfo.covarianceTrackingFrame[0] += trkParam.
SystErrorY2[iLayer];
 
  318          tfInfo.covarianceTrackingFrame[2] += trkParam.
SystErrorZ2[iLayer];
 
  325  mNTrackletsPerROF.resize(2);
 
  326  for (
auto& 
v : mNTrackletsPerROF) {
 
  327    v = bounded_vector<int>(mNrof + 1, 0, mMemoryPool.get());
 
  329  if (iteration == 0 || iteration == 3) {
 
  330    prepareClusters(trkParam, maxLayers);
 
  332  mTotalTracklets = {0, 0};
 
  333  if (maxLayers < trkParam.
NLayers) { 
 
  334    for (
size_t iLayer{0}; iLayer < maxLayers; ++iLayer) {
 
  340  mTotVertPerIteration.resize(1 + iteration);
 
  345  mMSangles.resize(trkParam.
NLayers);
 
  346  mPhiCuts.resize(mClusters.size() - 1, 0.f);
 
  348  float oneOverR{0.001f * 0.3f * std::abs(mBz) / trkParam.
TrackletMinPt};
 
  349  for (
unsigned int iLayer{0}; iLayer < 
nLayers; ++iLayer) {
 
  352    if (iLayer < mClusters.size() - 1) {
 
  353      const float& r1 = trkParam.
LayerRadii[iLayer];
 
  354      const float& r2 = trkParam.
LayerRadii[iLayer + 1];
 
  355      const float res1 = o2::gpu::CAMath::Hypot(trkParam.
PVres, mPositionResolution[iLayer]);
 
  356      const float res2 = o2::gpu::CAMath::Hypot(trkParam.
PVres, mPositionResolution[iLayer + 1]);
 
  357      const float cosTheta1half = o2::gpu::CAMath::Sqrt(1.f - math_utils::Sq(0.5f * r1 * oneOverR));
 
  358      const float cosTheta2half = o2::gpu::CAMath::Sqrt(1.f - math_utils::Sq(0.5f * r2 * oneOverR));
 
  359      float x = r2 * cosTheta1half - r1 * cosTheta2half;
 
  360      float delta = o2::gpu::CAMath::Sqrt(1.f / (1.f - 0.25f * math_utils::Sq(
x * oneOverR)) * (math_utils::Sq(0.25f * r1 * r2 * math_utils::Sq(oneOverR) / cosTheta2half + cosTheta1half) * math_utils::Sq(res1) + math_utils::Sq(0.25f * r1 * r2 * math_utils::Sq(oneOverR) / cosTheta1half + cosTheta2half) * math_utils::Sq(res2)));
 
  361      mPhiCuts[iLayer] = std::min(o2::gpu::CAMath::ASin(0.5f * 
x * oneOverR) + 2.f * mMSangles[iLayer] + delta, 
o2::constants::math::PI * 0.5f);
 
  365  for (
int iLayer{0}; iLayer < std::min((
int)mTracklets.size(), maxLayers); ++iLayer) {
 
  368    if (iLayer < (
int)mCells.size()) {
 
  371      mTrackletsLookupTable[iLayer].resize(mClusters[iLayer + 1].
size() + 1, 0);
 
  375    if (iLayer < (
int)mCells.size() - 1) {
 
  383template <
int nLayers>
 
  386  unsigned long size{0};
 
  387  for (
const auto& trkl : mTracklets) {
 
  390  for (
const auto& 
cells : mCells) {
 
  393  for (
const auto& cellsN : mCellsNeighbours) {
 
  394    size += 
sizeof(
int) * cellsN.size();
 
  396  return size + 
sizeof(
Road<nLayers - 2>) * mRoads.size();
 
 
  399template <
int nLayers>
 
  402  LOGP(info, 
"TimeFrame: Artefacts occupy {:.2f} MB", getArtefactsMemory() / 
constants::MB);
 
 
  405template <
int nLayers>
 
  409  mPValphaX.reserve(mPrimaryVertices.size());
 
  410  for (
auto& pv : mPrimaryVertices) {
 
  411    mPValphaX.emplace_back(std::array<float, 2>{o2::gpu::CAMath::Hypot(pv.getX(), pv.getY()), math_utils::computePhi(pv.getX(), pv.getY())});
 
 
  415template <
int nLayers>
 
  418  for (ushort iLayer = 0; iLayer < 2; ++iLayer) {
 
  419    for (
unsigned int iRof{0}; iRof < mNrof; ++iRof) {
 
  420      if (mMultiplicityCutMask[iRof]) {
 
  421        mTotalTracklets[iLayer] += mNTrackletsPerROF[iLayer][iRof];
 
  424    std::exclusive_scan(mNTrackletsPerROF[iLayer].begin(), mNTrackletsPerROF[iLayer].
end(), mNTrackletsPerROF[iLayer].begin(), 0);
 
  425    std::exclusive_scan(mNTrackletsPerCluster[iLayer].begin(), mNTrackletsPerCluster[iLayer].
end(), mNTrackletsPerClusterSum[iLayer].begin(), 0);
 
 
  429template <
int nLayers>
 
  432  for (uint32_t iLayer{0}; iLayer < getTracklets().size(); ++iLayer) {
 
  435    for (uint32_t iTracklet{0}; iTracklet < getTracklets()[iLayer].size(); ++iTracklet) {
 
  436      auto& trk = getTracklets()[iLayer][iTracklet];
 
  437      int currentId{trk.firstClusterIndex};
 
  438      if (currentId < prev) {
 
  439        LOG(info) << 
"First Cluster Index not increasing monotonically on L:T:ID:Prev " << iLayer << 
"\t" << iTracklet << 
"\t" << currentId << 
"\t" << prev;
 
  440      } 
else if (currentId == prev) {
 
  444          auto& lut{getTrackletsLookupTable()[iLayer - 1]};
 
  445          if (
count != lut[prev + 1] - lut[prev]) {
 
  446            LOG(info) << 
"LUT count broken " << iLayer - 1 << 
"\t" << prev << 
"\t" << 
count << 
"\t" << lut[prev + 1] << 
"\t" << lut[prev];
 
  453        auto& lut{getTrackletsLookupTable()[iLayer - 1]};
 
  454        if (iTracklet >= (uint32_t)(lut[currentId + 1]) || iTracklet < (uint32_t)(lut[currentId])) {
 
  455          LOG(info) << 
"LUT broken: " << iLayer - 1 << 
"\t" << currentId << 
"\t" << iTracklet;
 
 
  462template <
int nLayers>
 
  465  LOG(info) << 
"-------- Tracklet LUT " << 
i;
 
  467  for (
int j : mTrackletsLookupTable[
i]) {
 
  470  LOG(info) << s.str();
 
  471  LOG(info) << 
"--------";
 
 
  474template <
int nLayers>
 
  477  LOG(info) << 
"-------- Cell LUT " << 
i;
 
  479  for (
int j : mCellsLookupTable[
i]) {
 
  482  LOG(info) << s.str();
 
  483  LOG(info) << 
"--------";
 
 
  486template <
int nLayers>
 
  489  for (
unsigned int i{0}; 
i < mTrackletsLookupTable.size(); ++
i) {
 
  490    printTrackletLUTonLayer(
i);
 
 
  494template <
int nLayers>
 
  497  for (
unsigned int i{0}; 
i < mCellsLookupTable.size(); ++
i) {
 
  498    printCellLUTonLayer(
i);
 
 
  502template <
int nLayers>
 
  505  LOG(info) << 
"Vertices in ROF (nROF = " << mNrof << 
", lut size = " << mROFramesPV.size() << 
")";
 
  506  for (
unsigned int iR{0}; iR < mROFramesPV.size(); ++iR) {
 
  507    LOG(info) << mROFramesPV[iR] << 
"\t";
 
  509  LOG(info) << 
"\n\n Vertices:";
 
  510  for (
unsigned int iV{0}; iV < mPrimaryVertices.size(); ++iV) {
 
  511    LOG(info) << mPrimaryVertices[iV].getX() << 
"\t" << mPrimaryVertices[iV].getY() << 
"\t" << mPrimaryVertices[iV].getZ();
 
  513  LOG(info) << 
"--------";
 
 
  516template <
int nLayers>
 
  519  LOG(info) << 
"--------";
 
  520  for (
unsigned int iLayer{0}; iLayer < mROFramesClusters.size(); ++iLayer) {
 
  521    LOG(info) << 
"Layer " << iLayer;
 
  523    for (
auto value : mROFramesClusters[iLayer]) {
 
  526    LOG(info) << s.str();
 
 
  530template <
int nLayers>
 
  533  LOG(info) << 
"--------";
 
  534  for (
unsigned int iLayer{0}; iLayer < mNClustersPerROF.size(); ++iLayer) {
 
  535    LOG(info) << 
"Layer " << iLayer;
 
  537    for (
auto& 
value : mNClustersPerROF[iLayer]) {
 
  540    LOG(info) << s.str();
 
 
  544template <
int nLayers>
 
  547  LOG(info) << 
"Dumping slice of " << sliceSize << 
" rofs:";
 
  548  for (
int iROF{startROF}; iROF < startROF + sliceSize; ++iROF) {
 
  549    LOG(info) << 
"ROF " << iROF << 
" dump:";
 
  550    for (
unsigned int iLayer{0}; iLayer < mClusters.size(); ++iLayer) {
 
  551      LOG(info) << 
"Layer " << iLayer << 
" has: " << getClustersOnLayer(iROF, iLayer).size() << 
" clusters.";
 
  553    LOG(info) << 
"Number of seeding vertices: " << getPrimaryVertices(iROF).size();
 
  555    for (
auto& 
v : getPrimaryVertices(iROF)) {
 
  556      LOG(info) << 
"\t vertex " << iVertex++ << 
": x=" << 
v.getX() << 
" " 
  557                << 
" y=" << 
v.getY() << 
" z=" << 
v.getZ() << 
" has " << 
v.getNContributors() << 
" contributors.";
 
 
  562template <
int nLayers>
 
  572  auto initContainers = [&]<
typename Container>(Container& container, 
bool useExternal = 
false) {
 
  573    for (
auto& 
v : container) {
 
  574      initVector(
v, useExternal);
 
  578  initVector(mTotVertPerIteration);
 
  579  initContainers(mClusterExternalIndices);
 
  580  initContainers(mNTrackletsPerCluster);
 
  581  initContainers(mNTrackletsPerClusterSum);
 
  582  initContainers(mNClustersPerROF);
 
  583  initVector(mROFramesPV);
 
  584  initVector(mPrimaryVertices);
 
  586  initVector(mMSangles);
 
  587  initVector(mPhiCuts);
 
  588  initVector(mPositionResolution);
 
  589  initVector(mClusterSize);
 
  590  initVector(mPValphaX);
 
  591  initVector(mBogusClusters);
 
  592  initContainers(mTrackletsIndexROF);
 
  593  initContainers(mTracks);
 
  594  initContainers(mTracklets);
 
  595  initContainers(mCells);
 
  596  initContainers(mCellsNeighbours);
 
  597  initContainers(mCellsLookupTable);
 
  599  initVector(mVerticesContributorLabels);
 
  600  initContainers(mLinesLabels);
 
  601  initContainers(mTrackletLabels);
 
  602  initContainers(mCellLabels);
 
  603  initVector(mRoadLabels);
 
  604  initContainers(mTracksLabel);
 
  606  initContainers(mClusters, hasExternalHostAllocator());
 
  607  initContainers(mUsedClusters, hasExternalHostAllocator());
 
  608  initContainers(mUnsortedClusters, hasExternalHostAllocator());
 
  609  initContainers(mIndexTables, hasExternalHostAllocator());
 
  610  initContainers(mTrackingFrameInfo, hasExternalHostAllocator());
 
  611  initContainers(mROFramesClusters, hasExternalHostAllocator());
 
 
  614template <
int nLayers>
 
  642  if (!hasExternalHostAllocator()) {
 
  651  if (hasMCinformation()) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Definition of the ITSMFT compact cluster.
 
Definition of the GeometryTGeo class.
 
Definition of the SegmentationAlpide class.
 
Class for time synchronization of RawReader instances.
 
const Mat3D & getMatrixL2G(int sensID) const
 
HMPID cluster implementation.
 
const Mat3D & getMatrixT2L(int lay, int hba, int sta, int det) const
 
int getLayer(int index) const
Get chip layer, from 0.
 
float getSensorRefAlpha(int isn) const
 
static GeometryTGeo * Instance()
 
void fillMatrixCache(int mask) override
 
int getNPixels() const
Returns the number of fired pixels.
 
static constexpr unsigned short InvalidPatternID
 
static constexpr float PitchCol
 
static constexpr float PitchRow
 
math_utils::Point3D< T > getClusterCoordinates(const CompCluster &cl) const
 
float getErr2X(int n) const
Returns the error^2 on the x position of the COG for the n_th element.
 
int getNpixels(int n) const
Returns the number of fired pixels of the n_th element.
 
bool isGroup(int n) const
Returns true if the element corresponds to a group of rare topologies.
 
float getErr2Z(int n) const
Returns the error^2 on the z position of the COG for the n_th element.
 
GLsizei const GLfloat * value
 
GLint GLenum GLboolean GLsizei stride
 
GLenum GLuint GLint GLint layer
 
GLubyte GLubyte GLubyte GLubyte w
 
GLdouble GLdouble GLdouble z
 
void deepVectorClear(std::vector< T > &vec)
 
std::pmr::vector< T > bounded_vector
 
constexpr float DefClusError2Col
 
constexpr float DefClusError2Row
 
constexpr float DefClusErrorRow
 
constexpr float DefClusErrorCol
 
void clearResizeBoundedArray(std::array< bounded_vector< T >, S > &arr, size_t size, std::pmr::memory_resource *mr=nullptr, T def=T())
 
void clearResizeBoundedVector(bounded_vector< T > &vec, size_t sz, std::pmr::memory_resource *mr=nullptr, T def=T())
 
void checkTrackletLUTs()
Debug and printing.
 
void printTrackletLUTonLayer(int i)
 
void initialise(const int iteration, const TrackingParameters &trkParam, const int maxLayers=7, bool resetVertices=true)
 
void addPrimaryVertices(const bounded_vector< Vertex > &vertices, const int iteration)
 
void addPrimaryVerticesInROF(const bounded_vector< Vertex > &vertices, const int rofId, const int iteration)
 
void setMemoryPool(std::shared_ptr< BoundedMemoryResource > pool)
memory management
 
void printSliceInfo(const int, const int)
 
void prepareROFrameData(gsl::span< const o2::itsmft::ROFRecord > rofs, gsl::span< const itsmft::CompClusterExt > clusters)
 
void computeTrackletsPerROFScans()
 
void addPrimaryVerticesLabelsInROF(const bounded_vector< std::pair< MCCompLabel, float > > &labels, const int rofId)
 
void addPrimaryVerticesContributorLabelsInROF(const bounded_vector< MCCompLabel > &labels, const int rofId)
 
void addPrimaryVerticesLabels(bounded_vector< std::pair< MCCompLabel, float > > &labels)
 
int loadROFrameData(const o2::itsmft::ROFRecord &rof, gsl::span< const itsmft::Cluster > clusters, const dataformats::MCTruthContainer< MCCompLabel > *mcLabels=nullptr)
 
void fillPrimaryVerticesXandAlpha()
 
unsigned long getArtefactsMemory() const
 
void printCellLUTonLayer(int i)
 
void printArtefactsMemory() const
 
void addPrimaryVerticesContributorLabels(bounded_vector< MCCompLabel > &labels)
 
void resetROFrameData(size_t nROFs)
 
std::vector< float > LayerRadii
 
std::vector< float > SystErrorY2
 
std::vector< float > SystErrorZ2
 
float TrackletMinPt
Trackleting cuts.
 
std::vector< float > LayerResolution
 
std::vector< float > LayerxX0
 
int CellsPerRoad() const noexcept
 
int TrackletsPerRoad() const noexcept
 
std::vector< o2::ctf::BufferType > vec
 
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
 
std::vector< Cluster > clusters
 
std::vector< Cell > cells