Skip to content
Snippets Groups Projects
Select Git revision
  • nightly_master
  • master default
  • cmake_ana_dev
  • fairroot_target_dev
  • cmake_remaining_files
  • cmake_test_dev
  • cmake_mq_dev
  • cmake_reco_dev
  • cmake_test2
  • cmake_test1
  • cmake_test
  • cmake-dev
  • temp
  • APR21
  • dev_2021_20
  • dev_2021_19
  • RC3_APR21
  • dev_2021_18
  • RC2_APR21
  • dev_2021_17
  • RC1_APR21
  • dev_2021_16
  • dev_2021_15
  • dev_2021_14
  • dev_2021_13
  • dev_2021_12
  • dev_2021_11
  • dev_2021_10
  • dev_2021_09
  • dev_2021_08
  • dev_2021_07
  • dev_2021_06
32 results

CbmMQChannels.cxx

Blame
  • Forked from Computing / cbmroot
    Source project has a limited visibility.
    CbmTrdParModDigi.cxx 31.33 KiB
    /* Copyright (C) 2018-2020 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
       SPDX-License-Identifier: GPL-3.0-only
       Authors: Florian Uhlig [committer] */
    
    #include "CbmTrdParModDigi.h"
    
    #include "CbmTrdAddress.h"  // for CbmTrdAddress
    #include "CbmTrdPoint.h"    // for CbmTrdPoint
    
    #include <Logger.h>  // for LOG, Severity, Severity::debug2
    
    #include <TGeoManager.h>  // for TGeoManager, gGeoManager
    #include <TString.h>      // for TString
    #include <TVector3.h>     // for TVector3
    
    #include <iomanip>  // for setprecision, __iom_t5
    
    #include <math.h>    // for fabs
    #include <stdio.h>   // for printf
    #include <string.h>  // for strcmp
    
    //___________________________________________________________________
    CbmTrdParModDigi::CbmTrdParModDigi()
      : CbmTrdParMod("CbmTrdParModDigi", "TRD read-out definition")
      , fNofSectors(1)
      , fOrientation(0)
      , fAnodeWireOffset(0.375)
      , fAnodeWireSpacing(0.25)
      , fAnodeWireToPadPlaneDistance(0.35)
      , fX(0.)
      , fY(0.)
      , fZ(0.)
      , fSizeX(0)
      , fSizeY(0)
      , fSizeZ(0)
      , fSectorX()
      , fSectorY()
      , fSectorZ()
      , fSectorBeginX()
      , fSectorBeginY()
      , fSectorEndX()
      , fSectorEndY()
      , fSectorSizeX()
      , fSectorSizeY()
      , fPadSizeX()
      , fPadSizeY()
    {
    }
    //___________________________________________________________________
    CbmTrdParModDigi::CbmTrdParModDigi(Double_t x, Double_t y, Double_t z, Double_t sizex, Double_t sizey, Double_t sizez,
                                       Int_t nofSectors, Int_t orientation, const TArrayD& sectorSizeX,
                                       const TArrayD& sectorSizeY, const TArrayD& padSizeX, const TArrayD& padSizeY)
      : CbmTrdParMod("CbmTrdParModDigi", "TRD read-out definition")
      , fNofSectors(nofSectors)
      , fOrientation(orientation)
      , fAnodeWireOffset(0.375)
      , fAnodeWireSpacing(0.25)
      , fAnodeWireToPadPlaneDistance(0.35)
      , fX(x)
      , fY(y)
      , fZ(z)
      , fSizeX(sizex)
      , fSizeY(sizey)
      , fSizeZ(sizez)
      , fSectorX(nofSectors)
      , fSectorY(nofSectors)
      , fSectorZ(nofSectors)
      , fSectorBeginX(nofSectors)
      , fSectorBeginY(nofSectors)
      , fSectorEndX(nofSectors)
      , fSectorEndY(nofSectors)
      , fSectorSizeX(sectorSizeX)
      , fSectorSizeY(sectorSizeY)
      , fPadSizeX(padSizeX)
      , fPadSizeY(padSizeY)
    {
      /**  
      Calculate the coordinates of the begin and the end of each sector
      as well as the coordinates of the center of the sector
      In the moment it is assumed that there are sectors which have either
      in x- or y-direction the size of the chamber.
    */
      if (nofSectors > 1) {
        Double_t beginx, beginy, endx, endy;
        Double_t summed_sectsize;
        if (sectorSizeX.GetAt(0) == 2 * sizex) {  //substructure only in y-direction
          beginx          = 0;
          endx            = 2 * sizex;
          summed_sectsize = 0;
          for (Int_t i = 0; i < fNofSectors; i++) {
            if (0 == i) {
              beginy = 0.;
              endy   = sectorSizeY.GetAt(i);
              summed_sectsize += sectorSizeY.GetAt(i);
            }
            else {
              beginy = summed_sectsize;
              endy   = summed_sectsize += sectorSizeY.GetAt(i);
            }
            fSectorBeginX.AddAt(beginx, i);
            fSectorBeginY.AddAt(beginy, i);
            fSectorEndX.AddAt(endx, i);
            fSectorEndY.AddAt(endy, i);
            fSectorX.AddAt(beginx + (sectorSizeX.GetAt(i) / 2.), i);
            fSectorY.AddAt(beginy + (sectorSizeY.GetAt(i) / 2.), i);
            fSectorZ.AddAt(fZ, i);
          }
        }
        else {
          LOG(warn) << GetName()
                    << "::CbmTrdParModDigi - detect different information on "
                       "module size x : geometry="
                    << std::setprecision(5) << 2 * sizex << " CbmTrdPads.h=" << sectorSizeX.GetAt(0);
          beginy          = 0;
          endy            = 2 * sizey;
          summed_sectsize = 0;
          for (Int_t i = 0; i < fNofSectors; i++) {
            if (0 == i) {
              beginx = 0.;
              endx   = sectorSizeX.GetAt(i);
              summed_sectsize += sectorSizeX.GetAt(i);
            }
            else {
              beginx = summed_sectsize;
              endx   = summed_sectsize += sectorSizeX.GetAt(i);
            }
            fSectorBeginX.AddAt(beginx, i);
            fSectorBeginY.AddAt(beginy, i);
            fSectorEndX.AddAt(endx, i);
            fSectorEndY.AddAt(endy, i);
            fSectorX.AddAt(beginx + (sectorSizeX.GetAt(i) / 2.), i);
            fSectorY.AddAt(beginy + (sectorSizeY.GetAt(i) / 2.), i);
            fSectorZ.AddAt(fZ, i);
          }
        }
      }
      else {
        fSectorBeginX.AddAt(0., 0);
        fSectorBeginY.AddAt(0., 0);
        fSectorEndX.AddAt(sectorSizeX.GetAt(0), 0);
        fSectorEndY.AddAt(sectorSizeY.GetAt(0), 0);
        fSectorX.AddAt(x, 0);
        fSectorY.AddAt(y, 0);
        fSectorZ.AddAt(z, 0);
      }
    }
    
    //___________________________________________________________________________
    void CbmTrdParModDigi::Print(Option_t* opt) const
    {
      /** 
      Dump formated parameters for this module
    */
      printf(" CbmTrdParModDigi @ %5d ly[%d] idLy[%3d] rotation[%3ddeg] rows[%2d] "
             "cols[%3d]\n",
             fModuleId, CbmTrdAddress::GetLayerId(fModuleId), CbmTrdAddress::GetModuleId(fModuleId), fOrientation * 90,
             GetNofRows(), GetNofColumns());
      if (strcmp(opt, "all") != 0) return;
      printf("        center   [%7.2f %7.2f %7.2f]\n"
             "        size     [%7.2f %7.2f %7.2f]\n"
             "        anode    pitch[%5.3f] d2PP[%5.3f] off[%5.3f]\n"
             "        pads    ",
             fX, fY, fZ, fSizeX, fSizeY, fSizeZ, fAnodeWireSpacing, fAnodeWireToPadPlaneDistance, fAnodeWireOffset);
      for (Int_t isec(0); isec < fNofSectors; isec++)
        printf(" [c(%3d) r(%2d)]x[w(%4.2f) h(%5.2f)] area[%5.2fx%5.2f] limits "
               "x[%5.2f %5.2f] y[%5.2f %5.2f]\n                ",
               GetNofColumnsInSector(isec), GetNofRowsInSector(isec), fPadSizeX.At(isec), fPadSizeY.At(isec),
               fSectorSizeX[isec], fSectorSizeY[isec], fSectorBeginX[isec], fSectorEndX[isec], fSectorBeginY[isec],
               fSectorEndY[isec]);
      printf("\n");
    }
    
    //___________________________________________________________________________
    void CbmTrdParModDigi::ProjectPositionToNextAnodeWire(Double_t* local_point) const
    {
      /**
      Move the local point along y to the next anode wire position.
    
      20131009 - DE - checked OK
    */
    
      if (/*fAnodeWireOffset > 0.0 && */ fAnodeWireSpacing > 0.0) {  // wires must be defined defined
    
        // check, if the input is within the allowed range
        if (fabs(local_point[1]) - fSizeY > 1.e-3)
          LOG(error) << "CbmTrdParModDigi::ProjectPositionToNextAnodeWire - local "
                        "point must be within gas volume, y="
                     << std::setprecision(5) << local_point[1] << " module size " << fSizeY;
    
        Double_t ypos = local_point[1];
    
        LOG(debug2) << "local y before projection: " << std::setprecision(5) << local_point[1] << " cm";
    
        // make sure, local_point[1] is not negative (due to module center coordinate)
        // therefore transform to local corner first and then back at the end of operation
        local_point[1] += fSizeY;  // transform to module corner coordinates
    
        local_point[1] = Int_t(((local_point[1] - fAnodeWireOffset) / fAnodeWireSpacing) + 0.5) * fAnodeWireSpacing
                         + fAnodeWireOffset;  // find closest anode wire
    
        if (local_point[1] > 2 * fSizeY - fAnodeWireOffset)
          local_point[1] = 2 * fSizeY - fAnodeWireOffset;  // move inwards to the last anode wire
    
        local_point[1] -= fSizeY;  // transform back to module center coordinates
    
        LOG(debug2) << "local y after  projection: " << std::setprecision(5) << local_point[1] << " cm";
    
        // check, if we have left the anode wire grid
        if (fabs(local_point[1]) > fSizeY - fAnodeWireOffset)
          LOG(error) << "CbmTrdParModDigi::ProjectPositionToNextAnodeWire - local "
                        "point projected outside anode wire plane, from "
                     << std::setprecision(5) << ypos << " to " << std::setprecision(5) << local_point[1]
                     << " - last anode wire at " << std::setprecision(5) << fSizeY - fAnodeWireOffset;
      }
      else {
        LOG(error) << "CbmTrdParModDigi::ProjectPositionToNextAnodeWire: "
                      "fAnodeWireOffset and fAnodeWireSpacing not set. "
                      "ProjectPositionToNextAnodeWire can not be used.";
      }
    }
    
    //___________________________________________________________________________
    Int_t CbmTrdParModDigi::GetSector(const Double_t* local_point) const
    {
      /**
      Calculate the position in the chamber 
      with the origin of the local coordinate system 
      in the lower left corner of the chamber (looking upstream)
      x goes to the left, looking in beam direction, y goes upward
    */
    
      Double_t posx, posy;
    
      TransformToLocalCorner(local_point, posx, posy);
      for (Int_t i = 0; i < fNofSectors; i++) {
        if (posx >= fSectorBeginX[i] && posx <= fSectorEndX[i] && posy >= fSectorBeginY[i] && posy <= fSectorEndY[i]) {
          return i;
        }
      }
    
      LOG(error) << "CbmTrdParModDigi::GetSector: Could not find local point [" << local_point[0] << " " << local_point[1]
                 << "] in any of the sectors";
      Print("all");
      return -1;  // This should be never reached
    }
    
    //___________________________________________________________________________
    Int_t CbmTrdParModDigi::GetSector(Int_t npady, Int_t& rowId) const
    {
      /**  
      Calculate the pad coordinates in this sector from pad coordinates in the module e.g. in which sector is pad (20/28)
    */
    
      if ((npady < 0) || (npady > GetNofRows() - 1)) {
        LOG(error) << "CbmTrdParModDigi::GetSector - there is no such row number: " << npady;
        return -1;
      }
    
      Int_t secRows = 0;  // number of rows in sector
      Int_t nofRows = 0;  // number of rows in total
    
      if (fSectorSizeY.At(0) < fSizeY) {                                              // if there are sectors in y direction
        for (Int_t iSector = 0; iSector < fNofSectors; iSector++) {                   // for each sector
          secRows = (Int_t)(fSectorSizeY.At(iSector) / fPadSizeY.At(iSector) + 0.5);  // need to round for correct result
          if (npady < nofRows + secRows) {  // if we are in the sector containing the pad
            // note nypad = 12 is not in sector 0, with rowIds 0..11
            rowId = npady - nofRows;
    
            LOG(debug2) << "npady   : " << npady << " <= " << nofRows + secRows << "  rowId " << rowId << "  nRows(sec-1) "
                        << nofRows << "  sec " << iSector;
    
            if ((rowId < 0) || (rowId > GetNofRowsInSector(iSector) - 1))
              LOG(fatal) << "CbmTrdParModDigi::GetModuleRow rowId " << rowId << " of "
                         << GetNofRowsInSector(iSector) - 1
                         //<< " in moduleAddress " << fModuleAddress
                         << " is out of bounds!";
    
            return iSector;  // return sector
          }
          nofRows += secRows;  // sum up new total number of rows
        }
      }
      LOG(error) << "CbmTrdParModDigi::GetSector: Could not find pad in any of the sectors";
      return -1;  // This should be never reached
    }
    
    
    //___________________________________________________________________________
    Int_t CbmTrdParModDigi::GetNofColumns() const
    {
      /**
     * Get total number of pad columns in module  
     */
    
      Int_t nofColumns = 0;
      if (fSectorSizeX.At(0) < fSizeX) {
        for (Int_t i = 0; i < fNofSectors; i++) {
          nofColumns += (Int_t)(fSectorSizeX.At(i) / fPadSizeX.At(i) + 0.5);  // need to round for correct result
        }
      }
      else {
        nofColumns = (Int_t)(fSectorSizeX.At(0) / fPadSizeX.At(0) + 0.5);  // need to round for correct result
      }
      return nofColumns;
    }
    
    //___________________________________________________________________________
    Int_t CbmTrdParModDigi::GetNofRows() const
    {
      /** 
     * Get total number of pad rows in module  
    */
      Int_t nofRows = 0;
      if (fSectorSizeY.At(0) < fSizeY) {
        for (Int_t i = 0; i < fNofSectors; i++) {
          nofRows += (Int_t)(fSectorSizeY.At(i) / fPadSizeY.At(i) + 0.5);  // need to round for correct result
        }
      }
      else {
        nofRows = (Int_t)(fSectorSizeY.At(0) / fPadSizeY.At(0) + 0.5);  // need to round for correct result
      }
      return nofRows;
    }
    
    
    //___________________________________________________________________________
    Int_t CbmTrdParModDigi::GetNofColumnsInSector(Int_t i) const
    {
      return (Int_t)(fSectorSizeX.At(i) / fPadSizeX.At(i) + 0.5);  // need to round for correct result
    }
    
    
    //___________________________________________________________________________
    Int_t CbmTrdParModDigi::GetNofRowsInSector(Int_t i) const
    {
      return (Int_t)(fSectorSizeY.At(i) / fPadSizeY.At(i) + 0.5);  // need to round for correct result
    }
    
    
    //___________________________________________________________________________
    Int_t CbmTrdParModDigi::GetModuleRow(Int_t& sectorId, Int_t& rowId) const
    {
    
      // check limits
      if ((sectorId < 0) || (sectorId > GetNofSectors() - 1))
        LOG(fatal) << "CbmTrdParModDigi::GetModuleRow sectorId " << sectorId << " of "
                   << GetNofSectors() - 1
                   //<< " in moduleAddress " << fModuleAddress
                   << " is out of bounds!";
    
      // check limits
      if ((rowId < 0) || (rowId > GetNofRowsInSector(sectorId) - 1))
        LOG(fatal) << "CbmTrdParModDigi::GetModuleRow rowId " << rowId << " of "
                   << GetNofRowsInSector(sectorId) - 1
                   //<< " in moduleAddress " << fModuleAddress
                   << " is out of bounds!";
    
      Int_t moduleRowId = rowId;
    
      // calculate row number within module
      for (Int_t iSector = 0; iSector < sectorId; iSector++) {
        moduleRowId += (Int_t)(fSectorSizeY.At(iSector) / fPadSizeY.At(iSector) + 0.5);
        //     LOG(info) << "adding sector "   << iSector << " of " << sectorId;
      }
    
      //   if (sectorId == 0)
      //     // do nothing
      //   if (sectorId >= 1)
      //     moduleRowId += (Int_t)(fSectorSizeY.At(0) / fPadSizeY.At(0) + 0.5);
      //   if (sectorId >= 2)
      //     moduleRowId += (Int_t)(fSectorSizeY.At(1) / fPadSizeY.At(1) + 0.5);
    
      return moduleRowId;
    }
    
    
    //___________________________________________________________________________
    Int_t CbmTrdParModDigi::GetSectorRow(Int_t growId, Int_t& rowId) const
    {
      // check limits
      if ((growId < 0) || (growId >= GetNofRows()))
        LOG(fatal) << "CbmTrdParModDigi::GetSectorRow rowId " << growId << " of "
                   << GetNofRows()
                   //<< " in moduleAddress " << fModuleAddress
                   << " is out of bounds!";
    
      rowId = growId;
    
      // calculate row number within sector
      Int_t iSector(0);
      for (; iSector < 3; iSector++) {
        Int_t nr(GetNofRowsInSector(iSector));
        if (rowId - nr + 1 > 0) rowId -= nr;
        else
          break;
      }
    
      return iSector;
    }
    
    
    //___________________________________________________________________________
    Bool_t CbmTrdParModDigi::GetPadInfo(const Double_t* local_point, Int_t& sectorId, Int_t& columnId, Int_t& rowId) const
    {
      // check, if the input is within the allowed range
      if (fabs(local_point[0]) > fSizeX) {
        LOG(error) << "CbmTrdParModDigi::GetPadInfo - local point x must be within "
                      "gas volume, x="
                   << std::setprecision(8) << local_point[0] << " fSizeX=" << std::setprecision(8) << fSizeX;
        return kFALSE;
      }
      if (fabs(local_point[1]) > fSizeY) {
        LOG(error) << "CbmTrdParModDigi::GetPadInfo - local point y must be within "
                      "gas volume, y="
                   << std::setprecision(8) << local_point[1] << " fSizeY=" << std::setprecision(8) << fSizeY;
        return kFALSE;
      }
    
      Double_t posX, posY;
      TransformToLocalSector(local_point, posX, posY);
    
      // calculate in which sector the point is
      sectorId = GetSector(local_point);
    
      columnId = (Int_t)(posX / fPadSizeX.At(sectorId));
      rowId    = (Int_t)(posY / fPadSizeY.At(sectorId));
    
      return kTRUE;
    }
    
    //___________________________________________________________________________
    void CbmTrdParModDigi::GetPadInfo(const CbmTrdPoint* trdPoint, Int_t& sectorId, Int_t& columnId, Int_t& rowId) const
    {
      /**  
      Calculate point in the middle of the detector. This is
      for safety reasons, because the point at exit is slightly
      outside of the active volume. If one does not use a point
      in the detector one will get a wrong volume from the
      geomanager. Navigate to the correct volume to get all
      necessary information about this volume
    */
      Double_t x_mean = 0.5 * (trdPoint->GetXIn() + trdPoint->GetXOut());
      Double_t y_mean = 0.5 * (trdPoint->GetYIn() + trdPoint->GetYOut());
      Double_t z_mean = 0.5 * (trdPoint->GetZIn() + trdPoint->GetZOut());
      gGeoManager->FindNode(x_mean, y_mean, z_mean);
    
      TString curNode = gGeoManager->GetPath();
      if (!curNode.Contains("gas")) {
        // if the point is not in the gas volume print warning
        LOG(warn) << "This point is not in the trd gas";
        /*
        LOG(warn) << "x: " << std::setprecision(7) << trdPoint->GetXIn() << ", " << trdPoint->GetXOut();
        LOG(warn) << "y: " << std::setprecision(7) << trdPoint->GetYIn() << ", " << trdPoint->GetYOut();
        LOG(warn) << "z: " << std::setprecision(7) << trdPoint->GetZIn() << ", " << trdPoint->GetZOut();
        */
        sectorId = -1;
        return;
      }
    
      // Get the local point in local MC coordinates from
      // the geomanager. This coordinate system is rotated
      // if the chamber is rotated. This is corrected in
      // GetModuleInformation to have a
      // the same local coordinate system in all the chambers
      const Double_t* global_point = gGeoManager->GetCurrentPoint();
      Double_t local_point[3];
    
      gGeoManager->MasterToLocal(global_point, local_point);
    
      // 20131009 - DE - debuging output to check module orientation 0,1,2,3 with box generator
      if (fair::Logger::Logging(fair::Severity::debug2)) {
        // print module orientation
        LOG(debug2) << "module orientation: " << std::setprecision(5) << fOrientation;
    
        // print global coordinate
        LOG(debug2) << "global x: " << std::setprecision(5) << global_point[0] << " y: " << std::setprecision(5)
                    << global_point[1] << " z: " << std::setprecision(5) << global_point[2];
    
        // print local coordinate - relative to module center
        LOG(debug2) << "local  x: " << std::setprecision(5) << local_point[0] << " y: " << std::setprecision(5)
                    << local_point[1] << " z: " << std::setprecision(5) << local_point[2];
    
        // test projection to next anode wire
        Double_t proj_point[3];
        proj_point[0] = local_point[0];
        proj_point[1] = local_point[1];
        proj_point[2] = local_point[2];
    
        ProjectPositionToNextAnodeWire(proj_point);
    
        // print local coordinate - relative to module center
        LOG(debug2) << "proj   x: " << std::setprecision(5) << proj_point[0] << " y: " << std::setprecision(5)
                    << proj_point[1] << " z: " << std::setprecision(5) << proj_point[2];
    
        Double_t corner_point[3];
        corner_point[2] = local_point[2];
        TransformToLocalCorner(local_point, corner_point[0], corner_point[1]);
    
        // print local coordinate - relative to module corner
        LOG(debug2) << "corner x: " << std::setprecision(5) << corner_point[0] << " y: " << std::setprecision(5)
                    << corner_point[1] << " z: " << std::setprecision(5) << corner_point[2];
    
        LOG(debug2) << "pos    x: " << std::setprecision(5) << fX << " y: " << std::setprecision(5) << fY
                    << " z: " << std::setprecision(5) << fZ << " ori: " << std::setprecision(5) << fOrientation;
    
        LOG(debug2) << "size/2 x: " << std::setprecision(5) << fSizeX << " y: " << std::setprecision(5) << fSizeY
                    << " z: " << std::setprecision(5) << fSizeZ;
    
        Double_t sector_point[3];
        sector_point[2] = local_point[2];
        TransformToLocalSector(local_point, sector_point[0], sector_point[1]);
    
        // print local coordinate - relative to module sector
        LOG(debug2) << "sector x: " << std::setprecision(5) << sector_point[0] << " y: " << std::setprecision(5)
                    << sector_point[1] << " z: " << std::setprecision(5) << sector_point[2];
    
        // calculate in which sector the point is
        sectorId = GetSector(local_point);
        LOG(debug2) << "sectornr: " << std::setprecision(5) << sectorId;
    
        LOG(debug2) << "ncol    : " << std::setprecision(5) << GetNofColumns();
        LOG(debug2) << "nrow    : " << std::setprecision(5) << GetNofRows();
    
        // print local coordinate - relative to module sector
        LOG(debug2) << "sec2   x: " << std::setprecision(5) << fSectorBeginX.GetAt(2) << " y: " << std::setprecision(5)
                    << fSectorBeginY.GetAt(2);
        LOG(debug2) << "sec1   x: " << std::setprecision(5) << fSectorBeginX.GetAt(1) << " y: " << std::setprecision(5)
                    << fSectorBeginY.GetAt(1);
        LOG(debug2) << "sec0   x: " << std::setprecision(5) << fSectorBeginX.GetAt(0) << " y: " << std::setprecision(5)
                    << fSectorBeginY.GetAt(0);
    
        // get pad information
        Int_t s, c, r;
        GetPadInfo(local_point, s, c, r);
        LOG(debug2) << "pad sec: " << s << " col: " << c << " row: " << r;
      }  // debug2
    
      //  Int_t moduleAddress = CbmTrdAddress::GetModuleAddress(trdPoint->GetDetectorID());
      GetModuleInformation(
        /*moduleAddress, */ local_point, sectorId, columnId, rowId);
    }
    
    
    //___________________________________________________________________________
    void CbmTrdParModDigi::TransformToLocalCorner(const Double_t* local_point, Double_t& posX, Double_t& posY) const
    {
      /**  
      Transformation from local coordinate system 
      with origin in the middle of the module 
      into a system with the origin in the lower left corner (looking upstream).
      Since for both coordinate systems the orientation is the same 
      this is only a shift by the half size of the module in x- and y-direction
    
      20131009 - DE - checked OK for module orientations 0,1,2,3
    
    */
      posX = local_point[0] + fSizeX;
      posY = local_point[1] + fSizeY;
    }
    
    //___________________________________________________________________________
    void CbmTrdParModDigi::TransformToLocalSector(const Double_t* local_point, Double_t& posX, Double_t& posY) const
    {
      /**
       Transformation of the module coordinate system 
      with origin in the middle of the module 
      into a system with the origin in the lower left corner (looking upstream)
      of the sector the point is in. 
      First, transform in a system with origin in the lower left corner.
    
      20131009 - DE - checked OK for module orientations 0,1,2,3  
    */
      TransformToLocalCorner(local_point, posX, posY);
      Int_t sector = GetSector(local_point);
      posX -= fSectorBeginX.GetAt(sector);
      posY -= fSectorBeginY.GetAt(sector);
    }
    
    
    //___________________________________________________________________________
    void CbmTrdParModDigi::TransformToLocalPad(const Double_t* local_point, Double_t& posX, Double_t& posY) const
    {
      /**
      Transformation of the local module coordinate system 
      with origin in the middle of the module  
      into a system with the origin in the local pad center
      of the pad below the point.
      First, transform in a system with origin in the lower left sector.
    */
      Double_t sector_point[2];
      TransformToLocalSector(local_point, sector_point[0], sector_point[1]);
    
      //   TransformToLocalCorner(local_point, posX, posY);
      Int_t sectorId = GetSector(local_point);
    
      Double_t padx =
        (Int_t(sector_point[0] / fPadSizeX.At(sectorId)) + 0.5) * fPadSizeX.At(sectorId);  // x position of pad center
      Double_t pady =
        (Int_t(sector_point[1] / fPadSizeY.At(sectorId)) + 0.5) * fPadSizeY.At(sectorId);  // y position of pad center
    
      posX = sector_point[0] - padx;
      posY = sector_point[1] - pady;
    
      /*
      // print debug info
      LOG(info) << "sector x: " << std::setprecision(5) << sector_point[0] 
      << " y: " << std::setprecision(5) << sector_point[1];
    
      LOG(info) << "pad    x: " << std::setprecision(5) << padx 
      << " y: " << std::setprecision(5) << pady;
    
      LOG(info) << "diff   x: " << std::setprecision(5) << posX 
      << " y: " << std::setprecision(5) << posY;
    
      LOG(info) << "npad   x: " << std::setprecision(5) << padx / fPadSizeX.At(sectorId)
      << " y: " << std::setprecision(5) << pady / fPadSizeY.At(sectorId);
      */
    }
    
    
    //___________________________________________________________________________
    void CbmTrdParModDigi::TransformHitError(TVector3& hitErr) const
    {
      Double_t x, y;  // ,z;
      x = hitErr.X();
      y = hitErr.Y();
      //  z = hitErr.Z();
    
      //LOG(info) << "ori : " << fOrientation;
    
      if ((fOrientation == 1) || (fOrientation == 3)) {  // for orientations 1 or 3
        hitErr.SetX(y);                                  // swap errors
        hitErr.SetY(x);                                  // swap errors
    
        //    LOG(info) << " swapped x and y error";
        //    LOG(info) << "ori : " << fOrientation << " swapped x and y error";
      }
    }
    
    
    //___________________________________________________________________________
    void CbmTrdParModDigi::GetModuleInformation(
      //Int_t moduleAddress,
      const Double_t* local_point, Int_t& sectorId, Int_t& columnId, Int_t& rowId) const
    {
      // safety check. Up to now always correct, so could be removed.
      //   if (fModuleAddress != moduleAddress) {
      //     LOG(error) << "CbmTrdParModDigi::GetModuleInformation: This is wrong!";
      //   }
    
      Double_t posX, posY;
      TransformToLocalSector(local_point, posX, posY);
    
      // calculate in which sector the point is
      sectorId = GetSector(local_point);
    
      columnId = (Int_t)(posX / fPadSizeX.At(sectorId));
      rowId    = (Int_t)(posY / fPadSizeY.At(sectorId));
    }
    
    
    //___________________________________________________________________________
    void CbmTrdParModDigi::GetPadPosition(const Int_t sector, const Int_t col, const Int_t row, TVector3& padPos,
                                          TVector3& padPosErr) const
    {
      /** 
     * Get address of a pad, return position relative to module center
     */
    
      Double_t posX = 0;
      Double_t posY = 0;
      Double_t posZ = 0;
    
      Double_t padsizex = fPadSizeX.At(sector);
      Double_t padsizey = fPadSizeY.At(sector);
    
      // calculate position in sector coordinate system
      // with the origin in the lower left corner (looking upstream)
      posX = (((Double_t) col + 0.5) * padsizex);
      posY = (((Double_t) row + 0.5) * padsizey);
    
      // calculate position in module coordinate system
      // with the origin in the lower left corner (looking upstream)
      posX += fSectorBeginX.GetAt(sector);
      posY += fSectorBeginY.GetAt(sector);
    
      // calculate position in the module coordinate system
      // with origin in the middle of the module
      posX -= fSizeX;
      posY -= fSizeY;
      posZ = 0;
    
      // check limits
      if (fabs(posX) > fSizeX) LOG(fatal) << "CbmTrdParModDigi::GetPadPosition posX=" << posX << " is out of bounds!";
      // check limits
      if (fabs(posY) > fSizeY) LOG(fatal) << "CbmTrdParModDigi::GetPadPosition posY=" << posY << " is out of bounds!";
    
      padPos.SetXYZ(posX, posY, posZ);
      padPosErr.SetXYZ(padsizex / 2., padsizey / 2., 0.);
    }
    
    
    //___________________________________________________________________________
    void CbmTrdParModDigi::GetPadPosition(const Int_t padAddress, TVector3& padPos, TVector3& padPosErr) const
    {
      /** 
     * Get address of a pad, return position relative to module center
     */
    
      // Double_t posX = 0;
      // Double_t posY = 0;
      // Double_t posZ = 0;
    
      Int_t sectorId = CbmTrdAddress::GetSectorId(padAddress);
      Int_t rowId    = CbmTrdAddress::GetRowId(padAddress);
      Int_t columnId = CbmTrdAddress::GetColumnId(padAddress);
    
      return GetPadPosition(sectorId, rowId, columnId, padPos, padPosErr);
    }
    
    //___________________________________________________________________________
    void CbmTrdParModDigi::GetPadPosition(const Int_t padAddress, bool isCbmTrdDigiAddress, TVector3& padPos,
                                          TVector3& padPosErr) const
    {
      /** 
     * Get address of a pad, based on the channel address stored in the CbmTrdDigi
     */
      if (!isCbmTrdDigiAddress)
        LOG(error) << "Trying to get a CbmTrd PadPosition from DigiAddress format "
                      "function without digiAddress format";
    
    
      Int_t row = GetPadRow(padAddress);
      Int_t col = GetPadColumn(padAddress);
    
      Int_t srow(-1);
      Int_t sector = GetSectorRow(row, srow);
    
      return GetPadPosition(sector, col, srow, padPos, padPosErr);
    }
    
    //___________________________________________________________________________
    void CbmTrdParModDigi::GetPosition(
      //         Int_t moduleAddress,
      Int_t sectorId, Int_t columnId, Int_t rowId, TVector3& padPos, TVector3& padSize) const
    {
      /**  
      Calculate position in global coordinates 
      from digi information (sectorId, columnId, rowId).
      Returns two TVector3. One with the position
      and one with the padsize of the fired pad
    */
      //   if (fModuleAddress != moduleAddress) {
      //     LOG(error) << "CbmTrdParModDigi::GetPosition This is wrong!";
      //   }
    
      // check limits
      if ((sectorId < 0) || (sectorId > GetNofSectors() - 1))
        LOG(fatal) << "CbmTrdParModDigi::GetPosition sectorId " << sectorId << " of "
                   << GetNofSectors() - 1  //<< " in moduleAddress " << moduleAddress
                   << " is out of bounds!";
    
      // check limits
      if ((columnId < 0) || (columnId > GetNofColumnsInSector(sectorId) - 1))
        LOG(fatal) << "CbmTrdParModDigi::GetPosition columnId " << columnId << " of "
                   << GetNofColumnsInSector(sectorId) - 1
                   //<< " in moduleAddress " << moduleAddress
                   << " is out of bounds!";
    
      // check limits
      if ((rowId < 0) || (rowId > GetNofRowsInSector(sectorId) - 1))
        LOG(fatal) << "CbmTrdParModDigi::GetPosition rowId " << rowId << " of "
                   << GetNofRowsInSector(sectorId) - 1
                   //<< " in moduleAddress " << moduleAddress
                   << " is out of bounds!";
    
      Double_t local_point[3];
      Double_t padsizex = fPadSizeX.At(sectorId);
      Double_t padsizey = fPadSizeY.At(sectorId);
    
      // calculate position in sector coordinate system
      // with the origin in the lower left corner (looking upstream)
      local_point[0] = (((Double_t) columnId + 0.5) * padsizex);
      local_point[1] = (((Double_t) rowId + 0.5) * padsizey);
    
      // calculate position in module coordinate system
      // with the origin in the lower left corner (looking upstream)
      local_point[0] += fSectorBeginX.GetAt(sectorId);
      local_point[1] += fSectorBeginY.GetAt(sectorId);
      // local_point[i] must be >= 0 at this point
    
      // check limits
      if ((local_point[0] < 0) || (local_point[0] > 2 * fSizeX))
        LOG(fatal) << "CbmTrdParModDigi::GetPosition local_point[0]="
                   << local_point[0]
                   //<< " in moduleAddress " << moduleAddress
                   << " is out of bounds!";
      // check limits
      if ((local_point[1] < 0) || (local_point[1] > 2 * fSizeY))
        LOG(fatal) << "CbmTrdParModDigi::GetPosition local_point[1]="
                   << local_point[1]
                   //<< " in moduleAddress " << moduleAddress
                   << " is out of bounds!";
    
      // calculate position in the module coordinate system
      // with origin in the middle of the module
      local_point[0] -= fSizeX;
      local_point[1] -= fSizeY;
      local_point[2] = fSizeZ;
    
      // navigate to the correct module. (fX,fY,fZ)
      gGeoManager->FindNode(fX, fY, fZ);
    
      // get the local point in local MC coordinates from
      // the geomanager. This coordinate system is rotated,
      // if the chamber is rotated. This is corrected in
      // GetModuleInformation to have the same
      // local coordinate system in all the chambers
      Double_t global_point[3];  // global_point[3];
      gGeoManager->LocalToMaster(local_point, global_point);
    
      // calculate the position in the global coordinate system
      // with the origin in target
      Double_t posX = global_point[0];
      Double_t posY = global_point[1];
      Double_t posZ = global_point[2];
    
      padPos.SetXYZ(posX, posY, posZ);
      padSize.SetXYZ(padsizex, padsizey, 0.);
    }
    
    //___________________________________________________________________________
    Int_t CbmTrdParModDigi::GetPadColumn(const Int_t channelNumber) const
    {
      // calculate the pad column based on
      // the channeNumber as defined in the
      // CbmTrdDigi
    
      Int_t ncols = GetNofColumns();
      Int_t col   = channelNumber % ncols;
    
      return col;
    }
    
    //___________________________________________________________________________
    Int_t CbmTrdParModDigi::GetPadRow(const Int_t channelNumber) const
    {
      // calculate the pad row based on
      // the channeNumber as defined in the
      // CbmTrdDigi
    
      Int_t ncols = GetNofColumns();
      Int_t row   = channelNumber / ncols;
    
      return row;
    }
    
    
    ClassImp(CbmTrdParModDigi)