Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
DeUTSector.h 25.08 KiB
/*****************************************************************************\
* (c) Copyright 2000-2018 CERN for the benefit of the LHCb Collaboration      *
*                                                                             *
* This software is distributed under the terms of the GNU General Public      *
* Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING".   *
*                                                                             *
* In applying this licence, CERN does not waive the privileges and immunities *
* granted to it by virtue of its status as an Intergovernmental Organization  *
* or submit itself to any jurisdiction.                                       *
\*****************************************************************************/
#pragma once

#include "Detector/UT/ChannelID.h"
#include "Kernel/LineTraj.h"

#ifdef USE_DD4HEP

#  include "Detector/UT/DeUTSector.h"
using DeUTSector = LHCb::Detector::UT::DeUTSector;

#else

#  include "GaudiKernel/Plane3DTypes.h"
#  include "Kernel/LHCbConstants.h"
#  include "LHCbMath/LineTypes.h"
#  include "UTDet/DeUTBaseElement.h"
#  include "UTDet/DeUTModule.h"
#  include "UTDet/DeUTSensor.h"
#  include "UTDet/DeUTStave.h"
#  include <iomanip>
#  include <map>
#  include <memory>
#  include <string>
#  include <utility>
#  include <vector>

/** @class DeUTSector DeUTSector.h UTDet/DeUTSector.h
 *
 *  Class representing a UT Sector
 *
 *  @author Xuhao Yuan (based on code by Andy Beiter, Jianchun Wang, Matt Needham)
 *  @date   2021-03-29
 *
 */

static const CLID CLID_DeUTSector = 9320;

class DeUTSector : public DeUTBaseElement {

public:
  /** status enum
   * <b> For details on definitions see:</b>
   * \li <a href="http://ckm.physik.unizh.ch/software/det/deadStrips.php"><b>documentation</b></a><p>
   */
  enum Status {
    OK              = 0,
    Open            = 1,
    Short           = 2,
    Pinhole         = 3,
    ReadoutProblems = 4,
    NotBonded       = 5,
    LowGain         = 6,
    Noisy           = 7,
    OtherFault      = 9,
    Dead            = 10,
    UnknownStatus   = 100
  };

  /** lookup the enum corresponding to a string */
  friend Status toStatus( std::string_view str );

  /** lookup the string corresponding to a status enum */
  friend std::string toString( Status status );

  /** allow for Status to be used as a Gaudi::Property **/
  friend StatusCode    parse( Status&, std::string const& );
  friend std::ostream& toStream( Status status, std::ostream& os ) {
    return os << std::quoted( toString( status ), '\'' );
  }

  using Sensors = std::vector<DeUTSensor const*>;

  /** child type */
  using child_type = DeUTSensor;

  /** parent type */
  using stave_type  = DeUTStave;
  using module_type = DeUTModule;

  /** Constructor */
  using DeUTBaseElement::DeUTBaseElement;

  /**
   * Retrieves reference to class identifier
   * @return the class identifier for this class
   */
  static const CLID& classID() { return CLID_DeUTSector; }

  /**
   * another reference to class identifier
   * @return the class identifier for this class
   */
  const CLID& clID() const override { return DeUTSector::classID(); }

  /**
   * Retrieves the hybrid type
   * @return the hybrid type
   */
  enum struct HybridType { D, Q, N };
  friend std::string toString( HybridType t ) {
    switch ( t ) {
    case HybridType::D:
      return "D";
    case HybridType::Q:
      return "Q";
    case HybridType::N:
      return "N";
    }
    throw std::out_of_range( "unknown UTSector::HybridType" );
  }

  [[nodiscard]] HybridType hybridType() const { return m_hybridType; }

  /** initialization method
   * @return Status of initialisation
   */
  StatusCode initialize() override;

  /** column number */
  [[nodiscard]] unsigned int column() const { return m_column; }

  /** staveID number */
  [[nodiscard]] unsigned int staveID() const { return m_staveID; }

  /** row Number.... */
  [[nodiscard]] unsigned int row() const { return m_row; }

  /** production ID --> in fact parent ID */
  [[nodiscard]] unsigned int prodID() const { return m_prodID; }
  /** get the noise of the corresponding strip
   * @param aChannel channel
   * @return float noise of the strip
   */
  [[nodiscard]] float noise( LHCb::Detector::UT::ChannelID aChannel ) const;

  /** get the average noise in the sector
   * @return float average noise
   */
  [[nodiscard]] float sectorNoise() const;

  /** get the average noise of a beetle
   * @param beetle beetle number (1-4)
   * @return float average noise
   */
  [[nodiscard]] float beetleNoise( unsigned int beetle ) const;

  /** get the average noise of a beetle port
   * @param beetle beetle number (1-4)
   * @param port beetle port number (1-3)
   * @return float average noise
   */
  [[nodiscard]] float portNoise( unsigned int beetle, unsigned int port ) const;

  /** set the Noise of the corresponding strip
   * @param strip strip number
   * @param value Noise value
   */
  void setNoise( unsigned int strip, double value );

  /** set the Noise of the corresponding channel
   * @param chan channel
   * @param value Noise value
   */
  void setNoise( LHCb::Detector::UT::ChannelID chan, double value ) { setNoise( chan.strip(), value ); }

  /** set the Noise vector
   * @param values Noise vector
   */
  void setNoise( std::vector<double> values );

  /** get the Noise of the corresponding strip
   * @param aChannel channel
   * @return float noise of the strip
   */
  [[nodiscard]] float rawNoise( LHCb::Detector::UT::ChannelID aChannel ) const;

  /** get the average raw noise in the sector
   * @return float average noise
   */
  [[nodiscard]] float rawSectorNoise() const;

  /** get the average raw noise of a beetle
   * @param beetle beetle number (1-4)
   * @return float average noise
   */
  [[nodiscard]] float rawBeetleNoise( unsigned int beetle ) const;

  /** get the average raw noise of a beetle port
   * @param beetle beetle number (1-4)
   * @param port beetle port number (1-3)
   * @return float average noise
   */
  [[nodiscard]] float rawPortNoise( unsigned int beetle, unsigned int port ) const;

  /** get the common mode noise of the corresponding strip
   * @param aChannel channel
   * @return float noise of the strip
   */
  [[nodiscard]] float cmNoise( LHCb::Detector::UT::ChannelID aChannel ) const;

  /** get the average common noise in the sector
   * @return float average noise
   */
  [[nodiscard]] float cmSectorNoise() const;

  /** get the average common mode noise of a beetle
   * @param beetle beetle number (1-4)
   * @return float average noise
   */
  [[nodiscard]] float cmBeetleNoise( unsigned int beetle ) const;

  /** get the average common mode noise of a beetle port
   * @param beetle beetle number (1-4)
   * @param port beetle port number (1-3)
   * @return float average noise
   */
  [[nodiscard]] float cmPortNoise( unsigned int beetle, unsigned int port ) const;

  /** set the cmNoise of the corresponding strip
   * @param strip strip number
   * @param value cmNoise value
   */
  void setCMNoise( unsigned int strip, double value );

  /** set the cmNoise of the corresponding channel
   * @param chan channel
   * @param value cmNoise value
   */
  void setCMNoise( LHCb::Detector::UT::ChannelID chan, double value ) { setCMNoise( chan.strip(), value ); }

  /** set the cmNoise vector
   * @param values cmNoise vector
   */
  void setCMNoise( std::vector<double> values );

  /** set the ACD count from the electron number vector
   * @param values
   */
  void setADCConversion( std::vector<double> values );

  /** get the ADC count from the electron number
   * @param e electron number
   * @param aChannel channel
   * @return ADC count
   */
  [[nodiscard]] double toADC( double e, LHCb::Detector::UT::ChannelID aChannel ) const;

  /** get the ADC count from the electron number
   * @param e electron number
   * @param aStrip strip number
   * @return ADC count
   */
  [[nodiscard]] double toADC( double e, unsigned int aStrip ) const;

  /** get the electron number from the ADC count
   * @param val ADV count
   * @param aChannel channel
   * @return electron number
   */
  [[nodiscard]] double toElectron( double val, LHCb::Detector::UT::ChannelID aChannel ) const;

  /** get the electron number from the ADC count
   * @param val ADV count
   * @param aStrip strip number
   * @return electron number
   */
  [[nodiscard]] double toElectron( double val, unsigned int aStrip ) const;

  /** sector identfier
   * @return id
   */
  [[nodiscard]] unsigned int id() const { return m_id; }

  /** set sector id */
  DeUTSector& setID( const unsigned int id ) {
    m_id = id;
    return *this;
  }

  /** check whether contains
   *  @param  aChannel channel
   *  @return bool
   */
  [[nodiscard]] bool contains( LHCb::Detector::UT::ChannelID aChannel ) const override;

  /** detector pitch
   * @return pitch
   */
  [[nodiscard]] double pitch() const { return m_pitch; }

  /** number of strips
   * @return number of strips
   */
  [[nodiscard]] unsigned int nStrip() const { return m_nStrip; }

  /**
   * check if valid strip number
   *
   */
  [[nodiscard]] bool isStrip( unsigned int strip ) const;

  /** trajectory
   * @return trajectory for the fit
   */
  [[nodiscard]] LHCb::LineTraj<double> trajectory( LHCb::Detector::UT::ChannelID aChan, double offset ) const;

  [[nodiscard]] bool getStripflip() const { return m_stripflip; }

  [[nodiscard]] unsigned int firstStrip() const { return m_firstStrip; }

  [[nodiscard]] auto version() const { return m_version; }

  /** Trajectory<double> parameterized along y-axis */
  void trajectory( unsigned int strip, double offset, double& dxdy, double& dzdy, double& xAtYEq0, double& zAtYEq0,
                   double& ybegin, double& yend ) const;

  /**
   * @return total capacitance
   * ie sensors, cable + pitch adaptor
   */
  [[nodiscard]] double capacitance() const { return m_capacitance; }

  /**
   * @return sensor Capacitance
   */
  [[nodiscard]] double sensorCapacitance() const;

  /** strip length
   * @return strip length
   */
  [[nodiscard]] double stripLength() const { return m_stripLength; }

  /** thickness
   * @return double thickness
   */
  [[nodiscard]] double thickness() const { return m_thickness; }

  /** get the next channel left
   * @return next chan left
   */
  [[nodiscard]] LHCb::Detector::UT::ChannelID nextLeft( const LHCb::Detector::UT::ChannelID testChan ) const;

  /** get the next channel right
   * @return next chan left
   */
  [[nodiscard]] LHCb::Detector::UT::ChannelID nextRight( const LHCb::Detector::UT::ChannelID testChan ) const;

  /// Workaround to prevent hidden base class function
  [[nodiscard]] const std::type_info& type( const std::string& name ) const override {
    return ParamValidDataObject::type( name );
  }
  /**
   * @return std::string type
   */
  [[nodiscard]] const std::string& type() const { return m_type; }

  /** @return double stereo angle */
  [[nodiscard]] double angle() const { return m_angle; }

  /** @return double sin of stereo angle */
  [[nodiscard]] double sinAngle() const { return m_sinAngle; }

  /** @return cosine of stereo angle */
  [[nodiscard]] double cosAngle() const { return m_cosAngle; }

  /** @return check if is a stereo ladder */
  [[nodiscard]] bool isStereo() const { return m_isStereo; }

  /** beetle corresponding to channel  1-3 (IT) 1-4 (TT)*/
  [[nodiscard]] unsigned int beetle( const LHCb::Detector::UT::ChannelID& chan ) const {
    return beetle( chan.strip() + ( firstStrip() + 1 ) % 2 );
  }

  /** beetle corresponding to channel  1-3 (IT) 1-4 (TT)*/
  [[nodiscard]] unsigned int beetle( const unsigned int strip ) const {
    return ( ( strip - 1u ) / LHCbConstants::nStripsInBeetle ) + 1u;
  };

  /** n beetle
   * @return double nBeetles
   */
  [[nodiscard]] unsigned int nBeetle() const { return nStrip() / LHCbConstants::nStripsInBeetle; }

  /** measured efficiency
   * @ return double measured Eff
   */
  [[nodiscard]] double measEff() const { return m_measEff; }

  /** set measured Eff of sector  */
  void setMeasEff( const double measEff );

  /** Status of sector
   @return Status of readout sector
  */
  [[nodiscard]] Status sectorStatus() const { return m_status; }

  /** Status of the Beetle corresponding to strip */
  [[nodiscard]] Status beetleStatus( LHCb::Detector::UT::ChannelID chan ) const {
    return beetleStatus( beetle( chan ) );
  }

  /** Status of the Beetle with given id  1-3 (IT), 1-4 (TT) */
  [[nodiscard]] Status beetleStatus( unsigned int id ) const;

  /** vector of beetle status */
  [[nodiscard]] std::vector<DeUTSector::Status> beetleStatus() const;

  /** Status of channel */
  [[nodiscard]] Status stripStatus( LHCb::Detector::UT::ChannelID chan ) const;

  /** get vector of strip status for all strips in sector */
  [[nodiscard]] std::vector<Status> stripStatus() const;

  /** set the sector status */
  void setSectorStatus( const Status& newStatus );

  /** set vector of beetleStatus
   * @param unsigned int beetle [numbering from 1]
   * @param Status newStatus
   **/
  void setBeetleStatus( unsigned int beetle, const Status& newStatus );

  /** set vector of beetleStatus
   * @param LHCb::Detector::UT::ChannelID chan id of beetle
   * @param Status newStatus
   **/
  void setBeetleStatus( LHCb::Detector::UT::ChannelID chan, const Status& newStatus ) {
    setBeetleStatus( beetle( chan ), newStatus );
  }

  /** set vector of beetleStatus
   * @param unsigned int strip [numbering from 1]
   * @param Status newStatus
   **/
  void setStripStatus( unsigned int strip, const Status& newStatus );

  /** set vector of beetleStatus
   * @param LHCb::Detector::UT::ChannelID chan id of strip
   * @param Status newStatus
   **/
  void setStripStatus( LHCb::Detector::UT::ChannelID chan, const Status& newStatus ) {
    setStripStatus( chan.strip(), newStatus );
  };

  /** short cut for strip status ok
   * @return isOKStrip
   */
  [[nodiscard]] bool isOKStrip( LHCb::Detector::UT::ChannelID chan ) const {
    return stripStatus( chan ) == DeUTSector::OK;
  }

  /** short cut for hit error scaling factor
   * @return std::array all scaling factors
   */
  [[nodiscard]] std::array<double, 4> hitErrorFactors() const { return m_hitErrorFactors; }

  /** short cut for hit error scaling factor
   * @return scaling factor for a certain cluster size
   */
  [[nodiscard]] double hitErrorFactor( unsigned int clusterSize ) const {
    // support up to clusterSize=4
    return hitErrorFactors()[std::min( static_cast<int>( clusterSize ) - 1, 3 )];
  }

  /** strip to channel
   * @param strip
   * @return corresponding channel */
  [[nodiscard]] LHCb::Detector::UT::ChannelID stripToChan( const unsigned int strip ) const;

  /** version */
  [[nodiscard]] const std::string& versionString() const { return m_versionString; };

  /** dead width */
  [[nodiscard]] double deadWidth() const { return m_deadWidth; }

  /** print to stream */
  std::ostream& printOut( std::ostream& os ) const override;

  /** print to msgstream */
  MsgStream& printOut( MsgStream& os ) const override;

  /// Get given sensor
  [[nodiscard]] const DeUTSensor& sensor( unsigned int index ) const { return *m_sensors[index]; }

  /// number of sensors
  [[nodiscard]] unsigned int nSensors() const { return m_sensors.size(); }

  /// apply given callable to all sensors
  void applyToAllSensors( const std::function<void( DeUTSensor const& )>& func ) const {
    for ( auto* sensor : m_sensors ) { func( *sensor ); }
  }

  /** locate sensor based on a point
   * @return stave */
  [[nodiscard]] const DeUTSensor* findSensor( const Gaudi::XYZPoint& point ) const;

  /** find the middle sensor. rounding down if odd **/
  [[nodiscard]] const DeUTSensor* middleSensor() const { return m_sensors[m_sensors.size() / 2u]; }

  /** check if inside the active area
   * @param  point point in global frame
   * @param  tol   tolerance
   * @return bool isInside
   **/
  [[nodiscard]] bool globalInActive( const Gaudi::XYZPoint& point, Gaudi::XYZPoint tol = {0., 0., 0.} ) const;

  /** globalInActive
   * @param  point point in global frame
   * @param  tol   tolerance
   * @return bool in bondgap
   */
  [[nodiscard]] bool globalInBondGap( const Gaudi::XYZPoint& point, double tol = 0 ) const;

  /**
   * Nickname for the sensor
   **/
  [[nodiscard]] const std::string& nickname() const { return m_nickname; }

  /**
   * fraction active channels
   * @return bool fraction active
   */
  [[nodiscard]] double fractionActive() const;

  /** direct access to the status condition, for experts only */
  [[nodiscard]] const Condition* statusCondition() const { return condition( m_statusString ); }

  /** direct access to the noise condition, for experts only */
  [[nodiscard]] const Condition* noiseCondition() const { return condition( m_noiseString ); }

  /** x sense of local frame relative to global */
  [[nodiscard]] bool xInverted() const { return middleSensor()->xInverted(); }

  /** y sense of local frame relative to global */
  [[nodiscard]] bool yInverted() const { return middleSensor()->yInverted(); }

  [[nodiscard]] std::string conditionsPathName() const;

  /** getter for p0 */
  [[nodiscard]] Gaudi::XYZPoint get_p0() const { return m_p0; }

  /** getter for dp0di */
  [[nodiscard]] Gaudi::XYZVector get_dp0di() const { return m_dp0di; }

  /** getter for dy */
  [[nodiscard]] double get_dy() const { return m_dy; }

  /** getter for dxdy */
  [[nodiscard]] double get_dxdy() const { return m_dxdy; }

  /// get half length in x an y
  std::pair<double, double> halfLengths() const;

  Gaudi::XYZVector normalY() const { return globalPoint( 0, 1, 0 ) - globalPoint( 0, 0, 0 ); }

  /** ouput operator for class DeUTSector
   *  @see DeUTSector
   *  @see MsgStream
   *  @param os      reference to STL output stream
   *  @param aSector reference to DeUTSector object
   */
  friend std::ostream& operator<<( std::ostream& os, const DeUTSector& aSector ) { return aSector.printOut( os ); }

  /** ouput operator for class DeUTSector
   *  @see DeUTSector
   *  @see MsgStream
   *  @param os      reference to MsgStream output stream
   *  @param aSector reference to DeUTSector object
   */
  friend MsgStream& operator<<( MsgStream& os, const DeUTSector& aSector ) { return aSector.printOut( os ); }

  /** stream operator for status */
  friend std::ostream& operator<<( std::ostream& s, DeUTSector::Status e );

private:
  bool m_isStereo = false;

  StatusCode registerConditionsCallbacks();
  StatusCode cacheInfo();

  Sensors     m_sensors;
  double      m_thickness = 0.0;
  std::string m_nickname;

private:
  typedef std::map<unsigned int, Status> StatusMap;

  stave_type*  m_stave  = nullptr;
  module_type* m_module = nullptr;
  unsigned int m_row    = 0u;
  HybridType   m_hybridType;
  std::string  m_conditionPathName;

  std::string staveNumber( unsigned int chan, unsigned int reg ) const;

  StatusCode             updateStatusCondition();
  StatusCode             updateHitErrorFactorCondition();
  StatusCode             updateNoiseCondition();
  LHCb::LineTraj<double> createTraj( const unsigned int strip, const double offset ) const;
  void setStatusCondition( const std::string& type, const unsigned int entry, const DeUTSector::Status& newStatus );

  unsigned int m_firstStrip  = 1;
  unsigned int m_firstBeetle = 1;
  unsigned int m_id          = 0u;
  double       m_pitch       = 0.0;
  unsigned int m_nStrip      = 0u;
  double       m_capacitance = 0.0;
  double       m_stripLength = 0.0;
  // std::pair<double, double> m_range;
  unsigned int m_prodID = 0u;

  double      m_deadWidth = 0.0;
  std::string m_type;

  double           m_dxdy = 0.0;
  double           m_dzdy = 0.0;
  double           m_dy   = 0.0;
  Gaudi::XYZVector m_dp0di;
  Gaudi::XYZPoint  m_p0;
  double           m_angle    = 0.0;
  double           m_cosAngle = 0.0;
  double           m_sinAngle = 0.0;
  double           m_measEff  = 0.0;

  // status info
  Status      m_status = OK;
  StatusMap   m_beetleStatus;
  StatusMap   m_stripStatus;
  std::string m_statusString  = "Status";
  std::string m_versionString = "DC06";

  // Hit error scaling factors
  std::string           m_hitErrorFactorsString     = "HitError";
  std::string           m_hitErrorFactorsPathString = "/dd/Conditions/HitError/UT/HitError";
  std::array<double, 4> m_hitErrorFactors{1., 1., 1., 1.};

  // Noise info
  std::string         m_noiseString = "Noise";
  std::vector<double> m_noiseValues;
  std::vector<double> m_electronsPerADC;
  std::vector<double> m_cmModeValues;

  // Readout info, to determine stripflip based on new/old readout map
  bool m_stripflip = false;

  GeoVersion m_version = GeoVersion::v1;

  inline static const std::string m_readoutString     = "ReadoutMap";
  inline static const std::string m_readoutpathString = "/dd/Conditions/ReadoutConf/UT/ReadoutMap";

  unsigned int m_column{0};
  unsigned int m_staveID{0};

  static unsigned int face_map( unsigned int i ) {
    constexpr auto m = std::array{1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1,
                                  0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0,
                                  0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0};
    return m.at( i - 1 );
  }
  static unsigned int module_map( unsigned int i ) {
    constexpr auto m = std::array{0, 0, 1, 1, 2, 2, 2, 3, 3, 4, 4, 5, 5, 5, 6, 6, 7, 7, 0, 0, 1, 1, 2, 2, 2, 3, 3,
                                  3, 3, 4, 4, 4, 4, 5, 5, 5, 6, 6, 7, 7, 0, 0, 1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4,
                                  4, 5, 5, 5, 6, 6, 7, 7, 0, 0, 1, 1, 2, 2, 2, 3, 3, 4, 4, 5, 5, 5, 6, 6, 7, 7};
    return m.at( i - 1 );
  }
  static unsigned int sector_map( unsigned int i ) {
    constexpr auto m = std::array{0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1,
                                  0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1,
                                  0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0};
    return m.at( i - 1 );
  }
};

inline bool DeUTSector::contains( const LHCb::Detector::UT::ChannelID aChannel ) const {
  return aChannel.uniqueSector() == elementID().uniqueSector();
}

inline bool DeUTSector::isStrip( const unsigned int strip ) const {
  return strip >= m_firstStrip && strip < m_firstStrip + m_nStrip;
}

inline double DeUTSector::sensorCapacitance() const { return nSensors() * sensor( 0 ).capacitance(); }

inline void DeUTSector::trajectory( unsigned int strip, double offset, double& dxdy, double& dzdy, double& xAtYEq0,
                                    double& zAtYEq0, double& ybegin, double& yend ) const {
  auto i         = offset + strip;
  auto numstrips = ( ( m_stripflip && xInverted() ) ? ( m_nStrip - i ) : i );

  dxdy    = m_dxdy;
  dzdy    = m_dzdy;
  xAtYEq0 = m_p0.x() + numstrips * m_dp0di.x();
  zAtYEq0 = m_p0.z() + numstrips * m_dp0di.z();
  ybegin  = m_p0.y() + numstrips * m_dp0di.y();
  yend    = ybegin + m_dy;
}

inline DeUTSector::Status DeUTSector::beetleStatus( unsigned int id ) const {
  DeUTSector::Status theStatus = sectorStatus();
  if ( theStatus == DeUTSector::OK ) {
    if ( auto iter = m_beetleStatus.find( id ); iter != m_beetleStatus.end() ) theStatus = iter->second;
  }
  return theStatus;
}

inline DeUTSector::Status DeUTSector::stripStatus( LHCb::Detector::UT::ChannelID chan ) const {
  DeUTSector::Status theStatus = beetleStatus( chan );
  if ( theStatus == DeUTSector::OK ) {
    if ( auto iter = m_stripStatus.find( chan.strip() ); iter != m_stripStatus.end() ) theStatus = iter->second;
  }
  return theStatus;
}

inline std::vector<DeUTSector::Status> DeUTSector::beetleStatus() const {
  std::vector<Status> vec;
  vec.resize( nBeetle() );
  for ( unsigned int iBeetle = m_firstBeetle; iBeetle <= nBeetle(); ++iBeetle ) {
    if ( sectorStatus() != DeUTSector::OK ) {
      vec[iBeetle - 1] = sectorStatus();
      continue;
    }
    auto iter = m_beetleStatus.find( iBeetle );
    if ( iter != m_beetleStatus.end() ) {
      vec[iBeetle - 1] = iter->second;
    } else {
      vec[iBeetle - 1] = DeUTSector::OK;
    }
  } // nStrip
  return vec;
}

inline std::vector<DeUTSector::Status> DeUTSector::stripStatus() const {
  std::vector<Status> vec;
  vec.resize( nStrip() );
  for ( unsigned int iStrip = m_firstStrip; iStrip <= nStrip(); ++iStrip ) {
    if ( sectorStatus() != DeUTSector::OK ) {
      vec[iStrip - m_firstStrip] = sectorStatus();
      continue;
    }
    LHCb::Detector::UT::ChannelID chan = stripToChan( iStrip );
    if ( beetleStatus( chan ) != DeUTSector::OK ) {
      vec[iStrip - m_firstStrip] = beetleStatus( chan );
      continue;
    }
    auto iter                  = m_stripStatus.find( iStrip );
    vec[iStrip - m_firstStrip] = ( iter != m_stripStatus.end() ? iter->second : DeUTSector::OK );
  } // nStrip
  return vec;
}

inline LHCb::Detector::UT::ChannelID DeUTSector::stripToChan( unsigned int strip ) const {
  return isStrip( strip ) ? LHCb::Detector::UT::ChannelID( elementID().channelID() + strip - m_firstStrip )
                          : LHCb::Detector::UT::ChannelID( 0 );
}

[[deprecated( "please deref first" )]] inline std::ostream& operator<<( std::ostream& os, const DeUTSector* aSector ) {
  return os << *aSector;
}
[[deprecated( "please deref first" )]] inline MsgStream& operator<<( MsgStream& os, const DeUTSector* aSector ) {
  return os << *aSector;
}

#endif