45  mMaxBunchesFull = 
TIME_ORBIT / config.bunchSpacing;
 
   46  mMaxBunches = (
TIME_ORBIT - config.abortGapTime) / config.bunchSpacing;
 
   48  if (config.overlayRaw && 
chain->GetTPCTransformHelper() == 
nullptr) {
 
   49    GPUInfo(
"Overlay Raw Events requires TPC Fast Transform");
 
   50    throw std::exception();
 
   52  if (config.bunchSim) {
 
   53    if (config.bunchCount * config.bunchTrainCount > mMaxBunches) {
 
   54      GPUInfo(
"Invalid timeframe settings: too many colliding bunches requested!");
 
   55      throw std::exception();
 
   57    mTrainDist = mMaxBunches / config.bunchTrainCount;
 
   58    mCollisionProbability = (float)config.interactionRate * (
float)(mMaxBunchesFull * config.bunchSpacing / 1e9f) / (
float)(config.bunchCount * config.bunchTrainCount);
 
   59    GPUInfo(
"Timeframe settings: %d trains of %d bunches, bunch spacing: %d, train spacing: %dx%d, filled bunches %d / %d (%d), collision probability %f, mixing %d events", config.bunchTrainCount, config.bunchCount, config.bunchSpacing, mTrainDist, config.bunchSpacing,
 
   60            config.bunchCount * config.bunchTrainCount, mMaxBunches, mMaxBunchesFull, mCollisionProbability, mNEventsInDirectory);
 
   65  mEventUsed.resize(mNEventsInDirectory);
 
   66  if (config.noEventRepeat == 2) {
 
   67    memset(mEventUsed.data(), 0, mNEventsInDirectory * 
sizeof(mEventUsed[0]));
 
 
   74  if (config.overlayRaw) {
 
   76    for (uint32_t iSector = 0; iSector < NSECTORS; iSector++) {
 
   79        tmp.fTime += shiftTTotal;
 
   84    for (uint32_t iSector = 0; iSector < NSECTORS; iSector++) {
 
   87        tmp.z += iSector < NSECTORS / 2 ? shiftZ : -shiftZ;
 
   92      tmp.z += 
i < NSECTORS / 2 ? shiftZ : -shiftZ;
 
  100    uint32_t currentClusterTotal = 0;
 
  101    for (uint32_t iSector = 0; iSector < NSECTORS; iSector++) {
 
  102      uint32_t currentClusterSector = 0;
 
  105        float sign = iSector < NSECTORS / 2 ? 1 : -1;
 
  107          if (currentClusterSector != 
i) {
 
  117          currentClusterSector++;
 
  123        currentClusterTotal++;
 
  134    for (uint32_t 
i = 0; 
i < NSECTORS; 
i++) {
 
  142      GPUInfo(
"\tRemoved %u / %u clusters", removed, 
nClusters + removed);
 
 
  153  for (uint32_t 
i = 0; 
i < mShiftedEvents.size(); 
i++) {
 
  154    auto& 
ptr = std::get<0>(mShiftedEvents[
i]);
 
  155    for (uint32_t 
j = 0; 
j < NSECTORS; 
j++) {
 
  157      if (config.overlayRaw) {
 
  164    SetDisplayInformation(
i);
 
  166  uint32_t nClustersTotal = 0;
 
  167  uint32_t nClustersTotalRaw = 0;
 
  168  uint32_t nClustersSectorOffset[NSECTORS] = {0};
 
  169  for (uint32_t 
i = 0; 
i < NSECTORS; 
i++) {
 
  170    nClustersSectorOffset[
i] = nClustersTotal;
 
  174  if (nClustersTotalRaw && nClustersTotalRaw != nClustersTotal) {
 
  175    GPUError(
"Inconsitency between raw clusters and cluster data");
 
  176    throw std::exception();
 
  179    GPUError(
"Inconsitency between TPC clusters and MC labels");
 
  180    throw std::exception();
 
  185  uint32_t nTrackOffset = 0;
 
  186  uint32_t nColOffset = 0;
 
  187  uint32_t nClustersEventOffset[NSECTORS] = {0};
 
  188  for (uint32_t 
i = 0; 
i < mShiftedEvents.size(); 
i++) {
 
  189    auto& 
ptr = std::get<0>(mShiftedEvents[
i]);
 
  190    uint32_t inEventOffset = 0;
 
  191    for (uint32_t 
j = 0; 
j < NSECTORS; 
j++) {
 
  192      memcpy((
void*)&mChain->
mIOMem.
clusterData[
j][nClustersEventOffset[
j]], (
void*)
ptr.clusterData[
j], 
ptr.nClusterData[
j] * 
sizeof(
ptr.clusterData[
j][0]));
 
  193      if (nClustersTotalRaw) {
 
  194        memcpy((
void*)&mChain->
mIOMem.
rawClusters[
j][nClustersEventOffset[
j]], (
void*)
ptr.rawClusters[
j], 
ptr.nRawClusters[
j] * 
sizeof(
ptr.rawClusters[
j][0]));
 
  197        memcpy((
void*)&mChain->
mIOMem.
mcLabelsTPC[nClustersSectorOffset[
j] + nClustersEventOffset[
j]], (
void*)&
ptr.mcLabelsTPC[inEventOffset], 
ptr.nClusterData[
j] * 
sizeof(
ptr.mcLabelsTPC[0]));
 
  199      for (uint32_t k = 0; k < 
ptr.nClusterData[
j]; k++) {
 
  200        mChain->
mIOMem.
clusterData[
j][nClustersEventOffset[
j] + k].id = nClustersSectorOffset[
j] + nClustersEventOffset[
j] + k;
 
  202          for (int32_t l = 0; l < 3; l++) {
 
  204            if (
label.fMCID >= 0) {
 
  205              label.fMCID += nTrackOffset;
 
  211      nClustersEventOffset[
j] += 
ptr.nClusterData[
j];
 
  212      inEventOffset += 
ptr.nClusterData[
j];
 
  215    memcpy((
void*)&mChain->
mIOMem.
mcInfosTPC[nTrackOffset], (
void*)
ptr.mcInfosTPC, 
ptr.nMCInfosTPC * 
sizeof(
ptr.mcInfosTPC[0]));
 
  216    for (uint32_t 
j = 0; 
j < 
ptr.nMCInfosTPCCol; 
j++) {
 
  220    nTrackOffset += 
ptr.nMCInfosTPC;
 
  221    nColOffset += 
ptr.nMCInfosTPCCol;
 
  224  GPUInfo(
"Merged %d events, %u clusters total", (int32_t)mShiftedEvents.size(), nClustersTotal);
 
  226  mShiftedEvents.clear();
 
 
  231  if (config.nTotalEventsInTF && mNTotalCollisions >= config.nTotalEventsInTF) {
 
  235  int64_t nBunch = -
DRIFT_TIME / config.bunchSpacing;
 
  236  int64_t lastBunch = config.timeFrameLen / config.bunchSpacing;
 
  237  int64_t lastTFBunch = lastBunch - 
DRIFT_TIME / config.bunchSpacing;
 
  238  int32_t nCollisions = 0, nBorderCollisions = 0, nTrainCollissions = 0, nMultipleCollisions = 0, nTrainMultipleCollisions = 0;
 
  240  int32_t mcMin = -1, mcMax = -1;
 
  241  uint32_t nTotalClusters = 0;
 
  242  while (nBunch < lastBunch) {
 
  243    for (int32_t iTrain = 0; iTrain < config.bunchTrainCount && nBunch < lastBunch; iTrain++) {
 
  244      int32_t nCollisionsInTrain = 0;
 
  245      for (int32_t iBunch = 0; iBunch < config.bunchCount && nBunch < lastBunch; iBunch++) {
 
  246        const bool inTF = nBunch >= 0 && nBunch < lastTFBunch && (config.nTotalEventsInTF == 0 || nCollisions < mNTotalCollisions + config.nTotalEventsInTF);
 
  247        if (mcMin == -1 && inTF) {
 
  250        if (mcMax == -1 && nBunch >= 0 && !inTF) {
 
  253        int32_t nInBunchPileUp = 0;
 
  254        double randVal = mDisUniReal(inTF ? mRndGen2 : mRndGen1);
 
  255        double p = 
exp(-mCollisionProbability);
 
  257        while (randVal > p) {
 
  258          if (config.noBorder && (nBunch < 0 || nBunch >= lastTFBunch)) {
 
  261          if (nCollisionsInTrain >= mNEventsInDirectory) {
 
  262            GPUError(
"Error: insuffient events for mixing!");
 
  265          if (nCollisionsInTrain == 0 && config.noEventRepeat == 0) {
 
  266            memset(mEventUsed.data(), 0, mNEventsInDirectory * 
sizeof(mEventUsed[0]));
 
  274          if (config.noEventRepeat == 1) {
 
  275            useEvent = mSimBunchNoRepeatEvent;
 
  277            while (mEventUsed[useEvent = (inTF && config.eventStride ? (mEventStride += config.eventStride) : mDisUniInt(inTF ? mRndGen2 : mRndGen1)) % mNEventsInDirectory]) {
 
  281          if (config.noEventRepeat) {
 
  282            mSimBunchNoRepeatEvent++;
 
  284          mEventUsed[useEvent] = 1;
 
  285          double shift = (double)nBunch * (
double)config.bunchSpacing * (double)
TPCZ / (
double)
DRIFT_TIME;
 
  288            GPUError(
"Unexpected error");
 
  292          printf(
"Placing event %4d+%d (ID %4d) at z %7.3f (time %'dns) %s(collisions %4d, bunch %6ld, train %3d) (%'10d clusters, %'10d MC labels, %'10d track MC info)\n", nCollisions, nBorderCollisions, useEvent, shift, (int32_t)(nBunch * config.bunchSpacing), inTF ? 
" inside" : 
"outside",
 
  295          nCollisionsInTrain++;
 
  296          p2 *= mCollisionProbability / nInBunchPileUp;
 
  298          if (config.noEventRepeat && mSimBunchNoRepeatEvent >= mNEventsInDirectory) {
 
  302        if (nInBunchPileUp > 1) {
 
  303          nMultipleCollisions++;
 
  307      nBunch += mTrainDist - config.bunchCount;
 
  308      if (nCollisionsInTrain) {
 
  311      if (nCollisionsInTrain > 1) {
 
  312        nTrainMultipleCollisions++;
 
  316    nBunch += mMaxBunchesFull - mTrainDist * config.bunchTrainCount;
 
  318  mNTotalCollisions += nCollisions;
 
  319  GPUInfo(
"Timeframe statistics: collisions: %d+%d in %d trains (inside / outside), average rate %f (pile up: in bunch %d, in train %d)", nCollisions, nBorderCollisions, nTrainCollissions, (
float)nCollisions / (
float)(config.timeFrameLen - 
DRIFT_TIME) * 1e9, nMultipleCollisions,
 
  320          nTrainMultipleCollisions);
 
  324  if (!config.noBorder && mChain->
GetQA()) {
 
 
  332  for (int32_t iEventInTimeframe = 0; iEventInTimeframe < config.nMerge; iEventInTimeframe++) {
 
  334    if (config.shiftFirstEvent || iEventInTimeframe) {
 
  335      if (config.randomizeDistance) {
 
  336        shift = mDisUniReal(mRndGen2);
 
  337        if (config.shiftFirstEvent) {
 
  338          shift = (iEventInTimeframe + shift) * config.averageDistance;
 
  340          if (iEventInTimeframe == 0) {
 
  343            shift = (iEventInTimeframe - 0.5f + shift) * config.averageDistance;
 
  347        if (config.shiftFirstEvent) {
 
  348          shift = config.averageDistance * (iEventInTimeframe + 0.5f);
 
  350          shift = config.averageDistance * (iEventInTimeframe);
 
  357    if (
ReadEventShifted(iEvent * config.nMerge + iEventInTimeframe, shift) < 0) {