diff --git a/Detectors/Upgrades/ALICE3/CMakeLists.txt b/Detectors/Upgrades/ALICE3/CMakeLists.txt index 334bb13064783..301a82322636d 100644 --- a/Detectors/Upgrades/ALICE3/CMakeLists.txt +++ b/Detectors/Upgrades/ALICE3/CMakeLists.txt @@ -14,7 +14,6 @@ add_subdirectory(TRK) add_subdirectory(GlobalReconstruction) add_subdirectory(ECal) add_subdirectory(FD3) -add_subdirectory(FT3) add_subdirectory(FCT) add_subdirectory(AOD) add_subdirectory(IOTOF) diff --git a/Detectors/Upgrades/ALICE3/FT3/CMakeLists.txt b/Detectors/Upgrades/ALICE3/FT3/CMakeLists.txt deleted file mode 100644 index 2d9ff8a9ac78e..0000000000000 --- a/Detectors/Upgrades/ALICE3/FT3/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright 2019-2020 CERN and copyright holders of ALICE O2. -# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -# All rights not expressly granted are reserved. -# -# This software is distributed under the terms of the GNU General Public -# License v3 (GPL Version 3), copied verbatim in the file "COPYING". -# -# In applying this license 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. - -add_subdirectory(simulation) -add_subdirectory(base) diff --git a/Detectors/Upgrades/ALICE3/FT3/README.md b/Detectors/Upgrades/ALICE3/FT3/README.md deleted file mode 100644 index c11352607db85..0000000000000 --- a/Detectors/Upgrades/ALICE3/FT3/README.md +++ /dev/null @@ -1,34 +0,0 @@ - - -# ALICE 3 Tracker Endcaps - -This is top page for the FT3 detector documentation. - -## Specific detector setup - - -Configuration of the endcap disks can be done by setting values for the `FT3Base.layoutFT3` configurable, -the available options are presented in the following Table: - -| Option | Comments | -| --------------------------------- | ----------------------------------------------------------------------------------------------------------------- | -| `kSegmentedStave` | Segmentation of ML and OT disks: Modules are placed on staggered staves with user defined constants | -| `kSegmentedStaveOTOnly` (default) | Only OT disks are contain staves with modules, ML layers are segmented with strips of modules on front/back | -| `kSegmented` | Segmentation of ML and OT disk with strips of modules of chips on the front and back of a layer | -| `kTrapezoidal` | Simple trapezoidal disks (in both ML and OT), with `FT3Base.nTrapezoidalSegments=32` | -| `kCylindrical` | Simplest possible disks as TGeoTubes (ML and OT), bad for ACTS (wrong digi due to polar coorinates on disk sides) | - -Furthermore, there are more options in the case of stave segmentation -- for only OT or both. The user can set to cut the staves exactly on the nominal inner radii (true by default), and outer radii (false by default) of the disks. This exists since (planned) placements of sensors & staves often protrude out of the nominal radii to be more able to cover the nominal disk area. In addition, it is possible to draw reference circles in root for the stave segmented layouts for both the inner (red) and outer (blue) radii. This is off by default, yet can be toggled if the user wants to see how tight the tiling is to the nominal radii -- for visualisation purposes only. - -[ [Link to definitions](./base/include/FT3Base/FT3BaseParam.h) ] - -For example, see the command below to generate a geometry with the endcaps only, all layers with the stave geometry, and including reference circles of nominal radii for visualisation. -```bash -o2-sim-serial-run5 -n 1 -g pythia8hi -m FT3 \ - --configKeyValues "FT3Base.layoutFT3=kSegmented; FT3Base.drawReferenceCircles=true" -``` - - diff --git a/Detectors/Upgrades/ALICE3/FT3/base/CMakeLists.txt b/Detectors/Upgrades/ALICE3/FT3/base/CMakeLists.txt deleted file mode 100644 index 3e4925e78bd11..0000000000000 --- a/Detectors/Upgrades/ALICE3/FT3/base/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright 2019-2020 CERN and copyright holders of ALICE O2. -# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -# All rights not expressly granted are reserved. -# -# This software is distributed under the terms of the GNU General Public -# License v3 (GPL Version 3), copied verbatim in the file "COPYING". -# -# In applying this license 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. - -o2_add_library(FT3Base - SOURCES src/GeometryTGeo.cxx - SOURCES src/FT3BaseParam.cxx - PUBLIC_LINK_LIBRARIES O2::DetectorsBase O2::ITSMFTBase) - -o2_target_root_dictionary(FT3Base - HEADERS include/FT3Base/GeometryTGeo.h - HEADERS include/FT3Base/FT3BaseParam.h) diff --git a/Detectors/Upgrades/ALICE3/FT3/base/include/FT3Base/FT3BaseParam.h b/Detectors/Upgrades/ALICE3/FT3/base/include/FT3Base/FT3BaseParam.h deleted file mode 100644 index d7156b5c92582..0000000000000 --- a/Detectors/Upgrades/ALICE3/FT3/base/include/FT3Base/FT3BaseParam.h +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license 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. - -#ifndef ALICEO2_FT3_BASEPARAM_H_ -#define ALICEO2_FT3_BASEPARAM_H_ - -#include "CommonUtils/ConfigurableParam.h" -#include "CommonUtils/ConfigurableParamHelper.h" - -namespace o2 -{ -namespace ft3 -{ -// Parameters for FT3 (ML and OT disks) -enum eFT3Layout { - kCylindrical = 0, - kTrapezoidal, - kSegmented, - kSegmentedStave, - kSegmentedStaveOTOnly -}; -struct FT3BaseParam : public o2::conf::ConfigurableParamHelper { - // Geometry Builder parameters - eFT3Layout layoutFT3 = kSegmentedStaveOTOnly; - int nTrapezoidalSegments = 32; // for the simple trapezoidal disks - - // FT3Geometry::Telescope parameters - Int_t nLayers = 10; - Float_t z0 = -16.0; // First layer z position - Float_t zLength = 263.0; // Distance between first and last layers - Float_t etaIn = 4.5; - Float_t etaOut = 1.5; - Float_t Layerx2X0 = 0.01; - - // define tolerance allowed for staves to go outside nominal radii - double staveTolMLInner = 0.; - double staveTolMLOuter = 0.; - double staveTolOTInner = 0.; - double staveTolOTOuter = 0.; - - // What to place over x=0 line in case of full outer-outer stave: Gap or Module - bool placeSensorStackInMiddleOfStave = false; - - // Draw reference circles at inner and outer radius of stave layer, for visualisation - bool drawReferenceCircles = false; - - O2ParamDef(FT3BaseParam, "FT3Base"); -}; - -} // end namespace ft3 -} // end namespace o2 - -#endif // ALICEO2_FT3_BASEPARAM_H_ diff --git a/Detectors/Upgrades/ALICE3/FT3/base/include/FT3Base/GeometryTGeo.h b/Detectors/Upgrades/ALICE3/FT3/base/include/FT3Base/GeometryTGeo.h deleted file mode 100644 index 1941b543579db..0000000000000 --- a/Detectors/Upgrades/ALICE3/FT3/base/include/FT3Base/GeometryTGeo.h +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license 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. - -/// \file GeometryTGeo.h -/// \brief Definition of the GeometryTGeo class -/// \author cvetan.cheshkov@cern.ch - 15/02/2007 -/// \author ruben.shahoyan@cern.ch - adapted to ITSupg 18/07/2012 -/// \author rafael.pezzi@cern.ch - adapted to PostLS4EndCaps 25/06/2020 - -#ifndef ALICEO2_FT3_GEOMETRYTGEO_H_ -#define ALICEO2_FT3_GEOMETRYTGEO_H_ - -#include // for TGeoHMatrix -#include // for TObject -#include -#include -#include -#include "DetectorsBase/GeometryManager.h" -#include "DetectorsCommonDataFormats/DetID.h" -#include "ITSMFTBase/GeometryTGeo.h" -#include "MathUtils/Utils.h" -#include "Rtypes.h" // for Int_t, Double_t, Bool_t, UInt_t, etc - -class TGeoPNEntry; - -namespace o2 -{ -namespace ft3 -{ -/// GeometryTGeo is a simple interface class to TGeoManager. It is used in the simulation -/// in order to query the TGeo FT3 geometry. -/// RS: In order to preserve the static character of the class but make it dynamically access -/// geometry, we need to check in every method if the structures are initialized. To be converted -/// to singleton at later stage. - -class GeometryTGeo : public o2::itsmft::GeometryTGeo -{ - public: - typedef o2::math_utils::Transform3D Mat3D; - using DetMatrixCache::getMatrixL2G; - using DetMatrixCache::getMatrixT2GRot; - using DetMatrixCache::getMatrixT2L; - // this method is not advised for ITS: for barrel detectors whose tracking frame is just a rotation - // it is cheaper to use T2GRot - using DetMatrixCache::getMatrixT2G; - - static GeometryTGeo* Instance() - { - // get (create if needed) a unique instance of the object - if (!sInstance) { - sInstance = std::unique_ptr(new GeometryTGeo(true, 0)); - } - return sInstance.get(); - } - - // adopt the unique instance from external raw pointer (to be used only to read saved instance from file) - static void adopt(GeometryTGeo* raw); - - // constructor - // ATTENTION: this class is supposed to behave as a singleton, but to make it root-persistent - // we must define public default constructor. - // NEVER use it, it will throw exception if the class instance was already created - // Use GeometryTGeo::Instance() instead - GeometryTGeo(bool build = kFALSE, int loadTrans = 0 - /*o2::base::utils::bit2Mask(o2::TransformType::T2L, // default transformations to load - o2::TransformType::T2G, - o2::TransformType::L2G)*/ - ); - - /// Default destructor - ~GeometryTGeo() override = default; - - GeometryTGeo(const GeometryTGeo& src) = delete; - GeometryTGeo& operator=(const GeometryTGeo& geom) = delete; - - // implement filling of the matrix cache - using o2::itsmft::GeometryTGeo::fillMatrixCache; - void fillMatrixCache(int mask) override; - - /// Exract FT3 parameters from TGeo - void Build(int loadTrans = 0) override; - - void Print(Option_t* opt = "") const; - static const char* getFT3VolPattern() { return sVolumeName.c_str(); } - static const char* getFT3InnerVolPattern() { return sInnerVolumeName.c_str(); } - static const char* getFT3LayerPattern() { return sLayerName.c_str(); } - static const char* getFT3ChipPattern() { return sChipName.c_str(); } - static const char* getFT3SensorPattern() { return sSensorName.c_str(); } - static const char* getFT3PassivePattern() { return sPassiveName.c_str(); } - - static const char* composeSymNameFT3(Int_t d) { return Form("%s_%d", o2::detectors::DetID(o2::detectors::DetID::FT3).getName(), d); } - static const char* composeSymNameLayer(Int_t d, Int_t lr); - static const char* composeSymNameChip(Int_t d, Int_t lr); - static const char* composeSymNameSensor(Int_t d, Int_t lr); - - protected: - static std::string sInnerVolumeName; ///< Mother inner volume name - static std::string sVolumeName; ///< Mother volume name - static std::string sLayerName; ///< Layer name - static std::string sChipName; ///< Chip name - static std::string sSensorName; ///< Sensor name - static std::string sPassiveName; ///< Passive material name - - private: - static std::unique_ptr sInstance; ///< singletone instance - - ClassDefOverride(GeometryTGeo, 1); // FT3 geometry based on TGeo -}; -} // namespace ft3 -} // namespace o2 - -#endif \ No newline at end of file diff --git a/Detectors/Upgrades/ALICE3/FT3/base/src/FT3BaseLinkDef.h b/Detectors/Upgrades/ALICE3/FT3/base/src/FT3BaseLinkDef.h deleted file mode 100644 index 0a732ea1ec39b..0000000000000 --- a/Detectors/Upgrades/ALICE3/FT3/base/src/FT3BaseLinkDef.h +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license 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. - -#ifdef __CLING__ - -#pragma link off all globals; -#pragma link off all classes; -#pragma link off all functions; - -#pragma link C++ class o2::ft3::GeometryTGeo; -#pragma link C++ class o2::ft3::FT3BaseParam + ; -#pragma link C++ class o2::conf::ConfigurableParamHelper < o2::ft3::FT3BaseParam> + ; - -#endif diff --git a/Detectors/Upgrades/ALICE3/FT3/base/src/FT3BaseParam.cxx b/Detectors/Upgrades/ALICE3/FT3/base/src/FT3BaseParam.cxx deleted file mode 100644 index a5179299531a2..0000000000000 --- a/Detectors/Upgrades/ALICE3/FT3/base/src/FT3BaseParam.cxx +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license 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. - -#include "FT3Base/FT3BaseParam.h" -O2ParamImpl(o2::ft3::FT3BaseParam); diff --git a/Detectors/Upgrades/ALICE3/FT3/base/src/GeometryTGeo.cxx b/Detectors/Upgrades/ALICE3/FT3/base/src/GeometryTGeo.cxx deleted file mode 100644 index 73b2bc9b94eb8..0000000000000 --- a/Detectors/Upgrades/ALICE3/FT3/base/src/GeometryTGeo.cxx +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license 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. - -/// \file GeometryTGeo.cxx -/// \brief Implementation of the GeometryTGeo class -/// \author cvetan.cheshkov@cern.ch - 15/02/2007 -/// \author ruben.shahoyan@cern.ch - adapted to ITSupg 18/07/2012 -/// \author rafael.pezzi@cern.ch - adapted to ALICE 3 EndCaps 14/02/2021 - -// ATTENTION: In opposite to old AliITSgeomTGeo, all indices start from 0, not from 1!!! - -#include "FT3Base/GeometryTGeo.h" -#include "DetectorsBase/GeometryManager.h" -#include "MathUtils/Cartesian.h" - -#include // for LOG - -#include // for TGeoBBox -#include // for gGeoManager, TGeoManager -#include // for TGeoPNEntry, TGeoPhysicalNode -#include // for TGeoShape -#include // for Nint, ATan2, RadToDeg -#include // for TString, Form -#include "TClass.h" // for TClass -#include "TGeoMatrix.h" // for TGeoHMatrix -#include "TGeoNode.h" // for TGeoNode, TGeoNodeMatrix -#include "TGeoVolume.h" // for TGeoVolume -#include "TMathBase.h" // for Max -#include "TObjArray.h" // for TObjArray -#include "TObject.h" // for TObject - -#include // for isdigit -#include // for snprintf, NULL, printf -#include // for strstr, strlen - -using namespace TMath; -using namespace o2::ft3; -using namespace o2::detectors; - -ClassImp(o2::ft3::GeometryTGeo); - -std::unique_ptr GeometryTGeo::sInstance; - -std::string GeometryTGeo::sVolumeName = "FT3V"; ///< Mother volume name -std::string GeometryTGeo::sInnerVolumeName = "FT3Inner"; ///< Mother inner volume name -std::string GeometryTGeo::sLayerName = "FT3Layer"; ///< Layer name -std::string GeometryTGeo::sChipName = "FT3Chip"; ///< Chip name -std::string GeometryTGeo::sSensorName = "FT3Sensor"; ///< Sensor name -std::string GeometryTGeo::sPassiveName = "FT3Passive"; ///< Passive material name - -//__________________________________________________________________________ -GeometryTGeo::GeometryTGeo(bool build, int loadTrans) : o2::itsmft::GeometryTGeo(DetID::FT3) -{ - // default c-tor, if build is true, the structures will be filled and the transform matrices - // will be cached - if (sInstance) { - LOG(fatal) << "Invalid use of public constructor: o2::ft3::GeometryTGeo instance exists"; - // throw std::runtime_error("Invalid use of public constructor: o2::ft3::GeometryTGeo instance exists"); - } - - if (build) { - Build(loadTrans); - } -} - -//__________________________________________________________________________ -void GeometryTGeo::Build(int loadTrans) -{ - if (isBuilt()) { - LOG(warning) << "Already built"; - return; // already initialized - } - - if (!gGeoManager) { - // RSTODO: in future there will be a method to load matrices from the CDB - LOG(fatal) << "Geometry is not loaded"; - } - - fillMatrixCache(loadTrans); -} - -//__________________________________________________________________________ -const char* GeometryTGeo::composeSymNameLayer(Int_t d, Int_t lr) -{ - return Form("%s/%s%d", composeSymNameFT3(d), getFT3LayerPattern(), lr); -} - -//__________________________________________________________________________ -const char* GeometryTGeo::composeSymNameChip(Int_t d, Int_t lr) -{ - return Form("%s/%s%d", composeSymNameLayer(d, lr), getFT3ChipPattern(), lr); -} - -//__________________________________________________________________________ -const char* GeometryTGeo::composeSymNameSensor(Int_t d, Int_t lr) -{ - return Form("%s/%s%d", composeSymNameChip(d, lr), getFT3SensorPattern(), lr); -} - -//__________________________________________________________________________ -void GeometryTGeo::fillMatrixCache(int mask) -{ - // populate matrix cache for requested transformations - // -} diff --git a/Detectors/Upgrades/ALICE3/FT3/simulation/CMakeLists.txt b/Detectors/Upgrades/ALICE3/FT3/simulation/CMakeLists.txt deleted file mode 100644 index 23414d4ae7269..0000000000000 --- a/Detectors/Upgrades/ALICE3/FT3/simulation/CMakeLists.txt +++ /dev/null @@ -1,27 +0,0 @@ -# Copyright 2019-2020 CERN and copyright holders of ALICE O2. -# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -# All rights not expressly granted are reserved. -# -# This software is distributed under the terms of the GNU General Public -# License v3 (GPL Version 3), copied verbatim in the file "COPYING". -# -# In applying this license 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. - -o2_add_library(FT3Simulation - SOURCES - src/FT3Module.cxx - src/FT3Layer.cxx - src/Detector.cxx - PUBLIC_LINK_LIBRARIES O2::FT3Base - O2::ITSMFTSimulation - ROOT::Physics) - -o2_target_root_dictionary(FT3Simulation - HEADERS - include/FT3Simulation/FT3Module.h - include/FT3Simulation/Detector.h - include/FT3Simulation/FT3Layer.h) - -o2_data_file(COPY data DESTINATION Detectors/FT3/simulation) diff --git a/Detectors/Upgrades/ALICE3/FT3/simulation/data/simcuts.dat b/Detectors/Upgrades/ALICE3/FT3/simulation/data/simcuts.dat deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/Detectors/Upgrades/ALICE3/FT3/simulation/include/FT3Simulation/Detector.h b/Detectors/Upgrades/ALICE3/FT3/simulation/include/FT3Simulation/Detector.h deleted file mode 100644 index 361d94463ef56..0000000000000 --- a/Detectors/Upgrades/ALICE3/FT3/simulation/include/FT3Simulation/Detector.h +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license 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. - -/// \file Detector.h -/// \brief Definition of the Detector class - -#ifndef ALICEO2_FT3_DETECTOR_H_ -#define ALICEO2_FT3_DETECTOR_H_ - -#include "Rtypes.h" // for Int_t, Double_t, Float_t, Bool_t, etc - -#include "DetectorsBase/Detector.h" // for Detector -#include "DetectorsBase/GeometryManager.h" // for getSensID -#include "DetectorsCommonDataFormats/DetID.h" // for Detector -#include "ITSMFTSimulation/Hit.h" // for Hit - -#include "TArrayD.h" // for TArrayD -#include "TGeoManager.h" // for gGeoManager, TGeoManager (ptr only) -#include "TLorentzVector.h" // for TLorentzVector -#include "TVector3.h" // for TVector3 - -#include -#include - -class FairVolume; -class TGeoVolume; - -class TParticle; - -class TString; - -namespace o2::ft3 -{ -class GeometryTGeo; -class FT3BaseParam; -class FT3Layer; - -class Detector : public o2::base::DetImpl -{ - public: - /// Name : Detector Name - /// Active: kTRUE for active detectors (ProcessHits() will be called) - /// kFALSE for inactive detectors - Detector(Bool_t active); - - /// Default constructor - Detector(); - - /// Default destructor - ~Detector() override; - - /// Initialization of the detector is done here - void InitializeO2Detector() override; - - /// This method is called for each step during simulation (see FairMCApplication::Stepping()) - Bool_t ProcessHits(FairVolume* v = nullptr) override; - - /// Registers the produced collections in FAIRRootManager - void Register() override; - - /// Gets the produced collections - std::vector* getHits(Int_t iColl) const - { - if (iColl == 0) { - return mHits; - } - return nullptr; - } - - /// Has to be called after each event to reset the containers - void Reset() override; - - /// Base class to create the detector geometry - void ConstructGeometry() override; - - /// This method is an example of how to add your own point of type Hit to the clones array - o2::itsmft::Hit* addHit(int trackID, int detID, const TVector3& startPos, const TVector3& endPos, - const TVector3& startMom, double startE, double endTime, double eLoss, - unsigned char startStatus, unsigned char endStatus); - - Int_t chipVolUID(Int_t id) const { return o2::base::GeometryManager::getSensID(o2::detectors::DetID::FT3, id); } - - void EndOfEvent() override; - - void FinishPrimary() override { ; } - virtual void finishRun() { ; } - void BeginPrimary() override { ; } - void PostTrack() override { ; } - void PreTrack() override { ; } - - static constexpr int IdxForwardDisks = 0; - static constexpr int IdxBackwardDisks = 1; - /// Returns the number of layers - size_t getNumberOfLayers() const - { - if (mLayerName[IdxBackwardDisks].size() != mLayerName[IdxForwardDisks].size()) { - LOG(fatal) << "Number of layers in the two directions are different! Returning 0."; - } - return mLayerName[IdxBackwardDisks].size(); - } - - void buildBasicFT3(const FT3BaseParam& param); - void buildFT3V1(); - void buildFT3V3b(); - void buildFT3Scoping(); - void buildFT3NewVacuumVessel(); - void buildFT3ScopingV3(); - - protected: - std::array, 2> mLayerName; // Two sets of layer names, one per direction (forward/backward) - std::unordered_map mActiveSensorMap; - - private: - /// this is transient data about track passing the sensor - struct TrackData { // this is transient - bool mHitStarted; //! hit creation started - unsigned char mTrkStatusStart; //! track status flag - TLorentzVector mPositionStart; //! position at entrance - TLorentzVector mMomentumStart; //! momentum - double mEnergyLoss; //! energy loss - } mTrackData; //! - - /// Container for hit data - std::vector* mHits; - - /// Create the detector materials - virtual void createMaterials(); - - /// Create the detector geometry - void createGeometry(); - - /// Define the sensitive volumes of the geometry - void defineSensitiveVolumes(); - - Detector(const Detector&); - - Detector& operator=(const Detector&); - - std::array, 2> mLayers; // Two sets of layers, one per direction (forward/backward) - bool mIsPipeActivated = true; //! If Alice 3 pipe is present append inner disks to vacuum volume to avoid overlaps - - template - friend class o2::base::DetImpl; - ClassDefOverride(Detector, 2); -}; - -} // namespace o2::ft3 - -#ifdef USESHM -namespace o2 -{ -namespace base -{ -template <> -struct UseShm { - static constexpr bool value = true; -}; -} // namespace base -} // namespace o2 -#endif - -#endif diff --git a/Detectors/Upgrades/ALICE3/FT3/simulation/src/Detector.cxx b/Detectors/Upgrades/ALICE3/FT3/simulation/src/Detector.cxx deleted file mode 100644 index b6cd65f28ea9e..0000000000000 --- a/Detectors/Upgrades/ALICE3/FT3/simulation/src/Detector.cxx +++ /dev/null @@ -1,683 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license 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. - -/// \file Detector.cxx -/// \brief Implementation of the Detector class - -#include "FT3Simulation/Detector.h" - -#include "DetectorsBase/Stack.h" -#include "ITSMFTSimulation/Hit.h" -#include "SimulationDataFormat/TrackReference.h" - -#include "FT3Base/FT3BaseParam.h" -#include "FT3Base/GeometryTGeo.h" -#include "FT3Simulation/FT3Layer.h" - -// FairRoot includes -#include "FairDetector.h" // for FairDetector -#include "FairRootManager.h" // for FairRootManager -#include "FairRootManager.h" -#include "FairRun.h" // for FairRun -#include "FairRuntimeDb.h" // for FairRuntimeDb -#include "FairVolume.h" // for FairVolume - -#include "TGeoManager.h" // for TGeoManager, gGeoManager -#include "TGeoPcon.h" // for TGeoPcon -#include "TGeoTube.h" // for TGeoTube -#include "TGeoVolume.h" // for TGeoVolume, TGeoVolumeAssembly -#include "TString.h" // for TString, operator+ -#include "TVirtualMC.h" // for gMC, TVirtualMC -#include "TVirtualMCStack.h" // for TVirtualMCStack - -#include // for LOG, LOG_IF - -#include // for NULL, snprintf - -#define MAX_SENSORS 2000 - -class FairModule; - -class TGeoMedium; - -class TParticle; - -using namespace o2::ft3; -using o2::itsmft::Hit; - -//_________________________________________________________________________________________________ -Detector::Detector() - : o2::base::DetImpl("FT3", kTRUE), - mTrackData(), - mHits(o2::utils::createSimVector()) -{ -} - -//_________________________________________________________________________________________________ -void Detector::buildBasicFT3(const FT3BaseParam& param) -{ - // Build a basic parametrized FT3 detector with nLayers equally spaced between z_first and z_first+z_length - // Covering pseudo rapidity [etaIn,etaOut]. Silicon thinkness computed to match layer x/X0 - - LOG(info) << "Building FT3 Detector: Conical Telescope"; - - const int numberOfLayers = param.nLayers; - const auto z_first = param.z0; - const auto z_length = param.zLength; - const auto etaIn = param.etaIn; - const auto etaOut = param.etaOut; - const auto Layerx2X0 = param.Layerx2X0; - mLayerName[IdxBackwardDisks].resize(numberOfLayers); - mLayerName[IdxForwardDisks].resize(numberOfLayers); - - for (int direction : {IdxBackwardDisks, IdxForwardDisks}) { - for (int layerNumber = 0; layerNumber < numberOfLayers; layerNumber++) { - std::string layerName = GeometryTGeo::getFT3LayerPattern() + std::to_string(layerNumber + numberOfLayers * direction); - mLayerName[direction][layerNumber] = layerName; - - // Adds evenly spaced layers - const float layerZ = z_first + (layerNumber * z_length / numberOfLayers) * std::copysign(1, z_first); - const float rIn = std::abs(layerZ * std::tan(2.f * std::atan(std::exp(-etaIn)))); - const float rOut = std::abs(layerZ * std::tan(2.f * std::atan(std::exp(-etaOut)))); - const bool isMiddleLayer = layerNumber < 3; - auto& thisLayer = mLayers[direction].emplace_back(direction, layerNumber, layerName, layerZ, rIn, rOut, Layerx2X0, isMiddleLayer); - } - } -} - -//_________________________________________________________________________________________________ -void Detector::buildFT3V1() -{ - // Build FT3 detector according to - // https://indico.cern.ch/event/992488/contributions/4174473/attachments/2168881/3661331/tracker_parameters_werner_jan_11_2021.pdf - - LOG(info) << "Building FT3 Detector: V1"; - - const int numberOfLayers = 10; - const float sensorThickness = 30.e-4; - const float layersx2X0 = 1.e-2; - const std::vector> layersConfig{ - {26., .5, 3., 0.1f * layersx2X0}, // {z_layer, r_in, r_out, Layerx2X0} - {30., .5, 3., 0.1f * layersx2X0}, - {34., .5, 3., 0.1f * layersx2X0}, - {77., 3.5, 35., layersx2X0}, - {100., 3.5, 35., layersx2X0}, - {122., 3.5, 35., layersx2X0}, - {150., 3.5, 80.f, layersx2X0}, - {180., 3.5, 80.f, layersx2X0}, - {220., 3.5, 80.f, layersx2X0}, - {279., 3.5, 80.f, layersx2X0}}; - - mLayerName[IdxBackwardDisks].resize(numberOfLayers); - mLayerName[IdxForwardDisks].resize(numberOfLayers); - - for (auto direction : {IdxBackwardDisks, IdxForwardDisks}) { - for (int layerNumber = 0; layerNumber < numberOfLayers; layerNumber++) { - std::string directionName = std::to_string(direction); - std::string layerName = GeometryTGeo::getFT3LayerPattern() + directionName + std::string("_") + std::to_string(layerNumber); - mLayerName[direction][layerNumber] = layerName; - auto& z = layersConfig[layerNumber][0]; - - auto& rIn = layersConfig[layerNumber][1]; - auto& rOut = layersConfig[layerNumber][2]; - auto& x0 = layersConfig[layerNumber][3]; - - LOG(info) << "Adding Layer " << layerName << " at z = " << z; - // Add layers - const bool isMiddleLayer = layerNumber < 3; - auto& thisLayer = mLayers[direction].emplace_back(direction, layerNumber, layerName, z, rIn, rOut, x0, isMiddleLayer); - } - } -} - -//_________________________________________________________________________________________________ -void Detector::buildFT3V3b() -{ - // Build FT3 detector according to - // https://www.overleaf.com/project/6051acc870e39aaeb4653621 - - LOG(info) << "Building FT3 Detector: V3b"; - - const int numberOfLayers = 12; - float sensorThickness = 30.e-4; - float layersx2X0 = 1.e-2; - std::vector> layersConfig{ - {26., .5, 3., 0.1f * layersx2X0}, // {z_layer, r_in, r_out, Layerx2X0} - {30., .5, 3., 0.1f * layersx2X0}, - {34., .5, 3., 0.1f * layersx2X0}, - {77., 5.0, 35., layersx2X0}, - {100., 5.0, 35., layersx2X0}, - {122., 5.0, 35., layersx2X0}, - {150., 5.5, 80.f, layersx2X0}, - {180., 6.6, 80.f, layersx2X0}, - {220., 8.1, 80.f, layersx2X0}, - {279., 10.2, 80.f, layersx2X0}, - {340., 12.5, 80.f, layersx2X0}, - {400., 14.7, 80.f, layersx2X0}}; - - mLayerName[IdxBackwardDisks].resize(numberOfLayers); - mLayerName[IdxForwardDisks].resize(numberOfLayers); - - for (auto direction : {IdxBackwardDisks, IdxForwardDisks}) { - for (int layerNumber = 0; layerNumber < numberOfLayers; layerNumber++) { - std::string directionName = std::to_string(direction); - std::string layerName = GeometryTGeo::getFT3LayerPattern() + directionName + std::string("_") + std::to_string(layerNumber); - mLayerName[direction][layerNumber] = layerName; - auto& z = layersConfig[layerNumber][0]; - - auto& rIn = layersConfig[layerNumber][1]; - auto& rOut = layersConfig[layerNumber][2]; - auto& x0 = layersConfig[layerNumber][3]; - - LOG(info) << "Adding Layer " << layerName << " at z = " << z; - // Add layers - const bool isMiddleLayer = layerNumber < 3; - auto& thisLayer = mLayers[direction].emplace_back(direction, layerNumber, layerName, z, rIn, rOut, x0, isMiddleLayer); - } - } -} - -void Detector::buildFT3NewVacuumVessel() -{ - // Build the FT3 detector according to changes proposed during - // https://indico.cern.ch/event/1407704/ - // to adhere to the changes that were presented at the ALICE 3 Upgrade days in March 2024 - // Inner radius at C-side to 7 cm - // Inner radius at A-side stays at 5 cm - // 06.02.2025 update: IRIS layers are now in TRK - - LOG(info) << "Building FT3 Detector: After Upgrade Days March 2024 version"; - - const int numberOfLayers = 9; - const float sensorThickness = 30.e-4; - const float layersx2X0 = 1.e-2; - const std::vector> layersConfigCSide{ - {77., 7.0, 35., layersx2X0}, // {z_layer, r_in, r_out, Layerx2X0} - {100., 7.0, 35., layersx2X0}, - {122., 7.0, 35., layersx2X0}, - {150., 7.0, 68.f, layersx2X0}, - {180., 7.0, 68.f, layersx2X0}, - {220., 7.0, 68.f, layersx2X0}, - {260., 7.0, 68.f, layersx2X0}, - {300., 7.0, 68.f, layersx2X0}, - {350., 7.0, 68.f, layersx2X0}}; - - const std::vector> layersConfigASide{ - {77., 5.0, 35., layersx2X0}, // {z_layer, r_in, r_out, Layerx2X0} - {100., 5.0, 35., layersx2X0}, - {122., 5.0, 35., layersx2X0}, - {150., 5.0, 68.f, layersx2X0}, - {180., 5.0, 68.f, layersx2X0}, - {220., 5.0, 68.f, layersx2X0}, - {260., 5.0, 68.f, layersx2X0}, - {300., 5.0, 68.f, layersx2X0}, - {350., 5.0, 68.f, layersx2X0}}; - - mLayerName[IdxBackwardDisks].resize(numberOfLayers); - mLayerName[IdxForwardDisks].resize(numberOfLayers); - - for (auto direction : {IdxBackwardDisks, IdxForwardDisks}) { - for (int layerNumber = 0; layerNumber < numberOfLayers; layerNumber++) { - std::string directionName = std::to_string(direction); - std::string layerName = GeometryTGeo::getFT3LayerPattern() + directionName + std::string("_") + std::to_string(layerNumber); - mLayerName[direction][layerNumber] = layerName; - float z, rIn, rOut, x0; - if (direction == 0) { // C-Side - z = layersConfigCSide[layerNumber][0]; - rIn = layersConfigCSide[layerNumber][1]; - rOut = layersConfigCSide[layerNumber][2]; - x0 = layersConfigCSide[layerNumber][3]; - } else if (direction == 1) { // A-Side - z = layersConfigASide[layerNumber][0]; - rIn = layersConfigASide[layerNumber][1]; - rOut = layersConfigASide[layerNumber][2]; - x0 = layersConfigASide[layerNumber][3]; - } - - LOG(info) << "Adding Layer " << layerName << " at z = " << z; - // Add layers - const bool isMiddleLayer = layerNumber < 3; - auto& thisLayer = mLayers[direction].emplace_back(direction, layerNumber, layerName, z, rIn, rOut, x0, isMiddleLayer); - } - } -} - -void Detector::buildFT3ScopingV3() -{ - // Build the FT3 detector according to v3 layout - // https://indico.cern.ch/event/1596309/contributions/6728167/attachments/3190117/5677220/2025-12-10-AW-ALICE3planning.pdf - // Middle disks inner radius 10 cm - // Outer disks inner radius 20 cm - - LOG(info) << "Building FT3 Detector: v3 scoping version"; - - const int numberOfLayers = 6; - const float sensorThickness = 30.e-4; - const float layersx2X0 = 1.e-2; - using LayerConfig = std::array; // {z_layer, r_in, r_out, Layerx2X0} - const std::array layersConfigCSide{LayerConfig{77., 10.0, 35., layersx2X0}, - LayerConfig{100., 10.0, 35., layersx2X0}, - LayerConfig{122., 10.0, 35., layersx2X0}, - LayerConfig{150., 20.0, 68.f, layersx2X0}, - LayerConfig{180., 20.0, 68.f, layersx2X0}, - LayerConfig{220., 20.0, 68.f, layersx2X0}}; - - const std::array layersConfigASide{LayerConfig{77., 10.0, 35., layersx2X0}, - LayerConfig{100., 10.0, 35., layersx2X0}, - LayerConfig{122., 10.0, 35., layersx2X0}, - LayerConfig{150., 20.0, 68.f, layersx2X0}, - LayerConfig{180., 20.0, 68.f, layersx2X0}, - LayerConfig{220., 20.0, 68.f, layersx2X0}}; - const std::array enabled{true, true, true, true, true, true}; // To enable or disable layers for debug purpose - - for (int direction : {IdxBackwardDisks, IdxForwardDisks}) { - mLayerName[direction].clear(); - const std::array& layerConfig = (direction == IdxBackwardDisks) ? layersConfigCSide : layersConfigASide; - for (int layerNumber = 0; layerNumber < numberOfLayers; layerNumber++) { - if (!enabled[layerNumber]) { - continue; - } - const std::string directionName = std::to_string(direction); - const std::string layerName = GeometryTGeo::getFT3LayerPattern() + directionName + std::string("_") + std::to_string(layerNumber); - mLayerName[direction].push_back(layerName.c_str()); - const float z = layerConfig[layerNumber][0]; - const float rIn = layerConfig[layerNumber][1]; - const float rOut = layerConfig[layerNumber][2]; - const float x0 = layerConfig[layerNumber][3]; - LOG(info) << "buildFT3ScopingV3 -> Adding Layer " << layerNumber << "/" << numberOfLayers << " " << layerName << " at z = " << z; - // Add layers - const bool isMiddleLayer = layerNumber < 3; - auto& thisLayer = mLayers[direction].emplace_back(direction, layerNumber, layerName, z, rIn, rOut, x0, isMiddleLayer); - } - } -} - -//_________________________________________________________________________________________________ -void Detector::buildFT3Scoping() -{ - // Build FT3 detector according to the scoping document - - LOG(info) << "Building FT3 Detector: Scoping document version"; - - const int numberOfLayers = 12; - const float sensorThickness = 30.e-4; - const float layersx2X0 = 1.e-2; - const std::vector> layersConfig{ - {26., .5, 2.5, 0.1f * layersx2X0}, // {z_layer, r_in, r_out, Layerx2X0} - {30., .5, 2.5, 0.1f * layersx2X0}, - {34., .5, 2.5, 0.1f * layersx2X0}, - {77., 5.0, 35., layersx2X0}, - {100., 5.0, 35., layersx2X0}, - {122., 5.0, 35., layersx2X0}, - {150., 5.0, 68.f, layersx2X0}, - {180., 5.0, 68.f, layersx2X0}, - {220., 5.0, 68.f, layersx2X0}, - {260., 5.0, 68.f, layersx2X0}, - {300., 5.0, 68.f, layersx2X0}, - {350., 5.0, 68.f, layersx2X0}}; - - mLayerName[IdxBackwardDisks].resize(numberOfLayers); - mLayerName[IdxForwardDisks].resize(numberOfLayers); - - for (auto direction : {IdxBackwardDisks, IdxForwardDisks}) { - for (int layerNumber = 0; layerNumber < numberOfLayers; layerNumber++) { - std::string directionName = std::to_string(direction); - std::string layerName = GeometryTGeo::getFT3LayerPattern() + directionName + std::string("_") + std::to_string(layerNumber); - mLayerName[direction][layerNumber] = layerName; - auto& z = layersConfig[layerNumber][0]; - auto& rIn = layersConfig[layerNumber][1]; - auto& rOut = layersConfig[layerNumber][2]; - auto& x0 = layersConfig[layerNumber][3]; - - LOG(info) << "Adding Layer " << layerName << " at z = " << z; - // Add layers - const bool isMiddleLayer = layerNumber < 3; - auto& thisLayer = mLayers[direction].emplace_back(direction, layerNumber, layerName, z, rIn, rOut, x0, isMiddleLayer); - } - } -} - -//_________________________________________________________________________________________________ -Detector::Detector(bool active) - : o2::base::DetImpl("FT3", active), - mTrackData(), - mHits(o2::utils::createSimVector()) -{ - buildFT3ScopingV3(); // v3 Dec 25 -} - -//_________________________________________________________________________________________________ -Detector::Detector(const Detector& rhs) - : o2::base::DetImpl(rhs), - mTrackData(), - - /// Container for data points - mHits(o2::utils::createSimVector()) -{ - mLayerName = rhs.mLayerName; - mActiveSensorMap = rhs.mActiveSensorMap; -} - -//_________________________________________________________________________________________________ -Detector::~Detector() -{ - - if (mHits) { - // delete mHits; - o2::utils::freeSimVector(mHits); - } -} - -//_________________________________________________________________________________________________ -Detector& Detector::operator=(const Detector& rhs) -{ - // The standard = operator - // Inputs: - // Detector &h the sourse of this copy - // Outputs: - // none. - // Return: - // A copy of the sourse hit h - - if (this == &rhs) { - return *this; - } - - // base class assignment - base::Detector::operator=(rhs); - - mLayerName = rhs.mLayerName; - mActiveSensorMap = rhs.mActiveSensorMap; - mLayers = rhs.mLayers; - mTrackData = rhs.mTrackData; - - /// Container for data points - mHits = nullptr; - - return *this; -} - -//_________________________________________________________________________________________________ -void Detector::InitializeO2Detector() -{ - // Define the list of sensitive volumes - LOG(info) << "Initialize FT3 O2Detector"; - - defineSensitiveVolumes(); -} - -//_________________________________________________________________________________________________ -bool Detector::ProcessHits(FairVolume* vol) -{ - // This method is called from the MC stepping - if (!(fMC->TrackCharge())) { - return kFALSE; - } - - int volID = vol->getMCid(); - - auto it = mActiveSensorMap.find(volID); - if (it == mActiveSensorMap.end()) { - return kFALSE; // Not a sensitive volume - } - - int lay = it->second; - - auto stack = (o2::data::Stack*)fMC->GetStack(); - - bool startHit = false, stopHit = false; - unsigned char status = 0; - if (fMC->IsTrackEntering()) { - status |= Hit::kTrackEntering; - } - if (fMC->IsTrackInside()) { - status |= Hit::kTrackInside; - } - if (fMC->IsTrackExiting()) { - status |= Hit::kTrackExiting; - } - if (fMC->IsTrackOut()) { - status |= Hit::kTrackOut; - } - if (fMC->IsTrackStop()) { - status |= Hit::kTrackStopped; - } - if (fMC->IsTrackAlive()) { - status |= Hit::kTrackAlive; - } - - // track is entering or created in the volume - if ((status & Hit::kTrackEntering) || (status & Hit::kTrackInside && !mTrackData.mHitStarted)) { - startHit = true; - } else if ((status & (Hit::kTrackExiting | Hit::kTrackOut | Hit::kTrackStopped))) { - stopHit = true; - } - - // increment energy loss at all steps except entrance - if (!startHit) { - mTrackData.mEnergyLoss += fMC->Edep(); - } - if (!(startHit | stopHit)) { - return kFALSE; // do noting - } - if (startHit) { - mTrackData.mEnergyLoss = 0.; - fMC->TrackMomentum(mTrackData.mMomentumStart); - fMC->TrackPosition(mTrackData.mPositionStart); - mTrackData.mTrkStatusStart = status; - mTrackData.mHitStarted = true; - } - if (stopHit) { - TLorentzVector positionStop; - fMC->TrackPosition(positionStop); - // Retrieve the indices with the volume path - int chipindex = lay; - - Hit* p = addHit(stack->GetCurrentTrackNumber(), chipindex, mTrackData.mPositionStart.Vect(), positionStop.Vect(), - mTrackData.mMomentumStart.Vect(), mTrackData.mMomentumStart.E(), positionStop.T(), - mTrackData.mEnergyLoss, mTrackData.mTrkStatusStart, status); - // p->SetTotalEnergy(vmc->Etot()); - - // RS: not sure this is needed - // Increment number of Detector det points in TParticle - stack->addHit(GetDetId()); - } - - return kTRUE; -} - -//_________________________________________________________________________________________________ -void Detector::createMaterials() -{ - int ifield = 2; - float fieldm = 10.0; - o2::base::Detector::initFieldTrackingParams(ifield, fieldm); - - float tmaxfdSi = 0.1; // .10000E+01; // Degree - float stemaxSi = 0.0075; // .10000E+01; // cm - float deemaxSi = 0.1; // 0.30000E-02; // Fraction of particle's energy 0RegisterAny(addNameTo("Hit").data(), mHits, kTRUE); - } -} - -//_________________________________________________________________________________________________ -void Detector::Reset() -{ - if (!o2::utils::ShmManager::Instance().isOperational()) { - mHits->clear(); - } -} - -//_________________________________________________________________________________________________ -void Detector::ConstructGeometry() -{ - // Create detector materials - createMaterials(); - - // Construct the detector geometry - createGeometry(); -} - -//_________________________________________________________________________________________________ -void Detector::createGeometry() -{ - - TGeoVolume* volFT3 = new TGeoVolumeAssembly(GeometryTGeo::getFT3VolPattern()); - TGeoVolume* volIFT3 = new TGeoVolumeAssembly(GeometryTGeo::getFT3InnerVolPattern()); - - LOG(info) << "FT3: createGeometry volume name = " << GeometryTGeo::getFT3VolPattern(); - - TGeoVolume* vALIC = gGeoManager->GetVolume("barrel"); - if (!vALIC) { - LOG(fatal) << "Could not find the top volume"; - } - - TGeoVolume* A3IPvac = gGeoManager->GetVolume("OUT_PIPEVACUUM"); - if (!A3IPvac) { - LOG(info) << "Running simulation with no beam pipe."; - } - - // This will need to adapt to the new scheme - if (!A3IPvac) { - for (int direction : {IdxBackwardDisks, IdxForwardDisks}) { // Backward layers at mLayers[0]; Forward layers at mLayers[1] - const std::string directionString = direction ? "Forward" : "Backward"; - LOG(info) << " Creating FT3 without beampipe " << directionString << " layers:"; - for (int iLayer = 0; iLayer < mLayers[direction].size(); iLayer++) { - mLayers[direction][iLayer].createLayer(volFT3); - } - } - vALIC->AddNode(volFT3, 2, new TGeoTranslation(0., 30., 0.)); - } else { // If beampipe is enabled append inner disks to beampipe filling volume, this should be temporary. - for (int direction : {IdxBackwardDisks, IdxForwardDisks}) { - const std::string directionString = direction ? "Forward" : "Backward"; - LOG(info) << " Creating FT3 " << directionString << " layers:"; - for (int iLayer = 0; iLayer < mLayers[direction].size(); iLayer++) { - LOG(info) << " Creating " << directionString << " layer " << iLayer; - if (mLayers[direction][iLayer].getIsInMiddleLayer()) { // ML disks - mLayers[direction][iLayer].createLayer(volIFT3); - } else { - mLayers[direction][iLayer].createLayer(volFT3); - } - } - } - A3IPvac->AddNode(volIFT3, 2, new TGeoTranslation(0., 0., 0.)); - vALIC->AddNode(volFT3, 2, new TGeoTranslation(0., 30., 0.)); - } -} - -//_________________________________________________________________________________________________ -void Detector::defineSensitiveVolumes() -{ - TGeoManager* geoManager = gGeoManager; - - // Get the flat list of ALL volumes present in the geometry - TObjArray* allVolumes = geoManager->GetListOfVolumes(); - int nVolumes = allVolumes->GetEntriesFast(); - - LOG(info) << "Adding FT3 Sensitive Volumes by iterating over all geometry volumes..."; - - for (int direction : {IdxBackwardDisks, IdxForwardDisks}) { - for (int iLayer = 0; iLayer < getNumberOfLayers(); iLayer++) { - int iSens = 0; - - // Build the "signatures" (prefixes) of the names for the various layouts for this specific layer and direction: - - // 1. Trapezoidal/Cylindrical (format: FT3Sensor__) - std::string sig1 = Form("%s_%d_%d", GeometryTGeo::getFT3SensorPattern(), direction, iLayer); - - // 2. Segmented front/back (format: FT3Sensor_front___...) - std::string sig2 = "FT3Sensor_front_" + std::to_string(iLayer) + "_" + std::to_string(direction); - std::string sig3 = "FT3Sensor_back_" + std::to_string(iLayer) + "_" + std::to_string(direction); - - // 3. SegmentedStave (format: FT3Sensor___...) - // Add the trailing underscore to avoid confusing it with sig1 - std::string sig4 = "FT3Sensor_" + std::to_string(direction) + "_" + std::to_string(iLayer) + "_"; - - // Iterate over all existing volumes to find matches - for (int i = 0; i < nVolumes; ++i) { - TGeoVolume* v = (TGeoVolume*)allVolumes->At(i); - std::string vName = v->GetName(); - - // Explicitly exclude the inactive silicon regions created in FT3Module - if (vName.find("Inactive") != std::string::npos || vName.find("inactive") != std::string::npos) { - continue; - } - - // Check if the volume name matches one of our active sensors - bool isMatch = false; - if (vName == sig1) { - isMatch = true; // Exact match for Trapezoidal/Cylindrical layouts - } else if (vName.find(sig2) == 0 || vName.find(sig3) == 0 || vName.find(sig4) == 0) { - isMatch = true; // Prefix match for Segmented and SegmentedStave layouts - } - - if (isMatch) { - AddSensitiveVolume(v); - int volID = gMC ? TVirtualMC::GetMC()->VolId(vName.c_str()) : 0; - if (volID > 0) { - mActiveSensorMap[volID] = iLayer; - } - iSens++; - } - } - - if (iSens == 0) { - LOG(error) << "NO sensitive volume found for direction " << direction << ", layer " << iLayer; - } else { - LOG(info) << iSens << " sensitive volume(s) added for direction " << direction << " layer " << iLayer; - } - } - } -} - -//_________________________________________________________________________________________________ -Hit* Detector::addHit(int trackID, int detID, const TVector3& startPos, const TVector3& endPos, - const TVector3& startMom, double startE, double endTime, double eLoss, unsigned char startStatus, - unsigned char endStatus) -{ - mHits->emplace_back(trackID, detID, startPos, endPos, startMom, startE, endTime, eLoss, startStatus, endStatus); - return &(mHits->back()); -} - -ClassImp(o2::ft3::Detector); diff --git a/Detectors/Upgrades/ALICE3/FT3/simulation/src/FT3SimulationLinkDef.h b/Detectors/Upgrades/ALICE3/FT3/simulation/src/FT3SimulationLinkDef.h deleted file mode 100644 index 3908f9aa71e5e..0000000000000 --- a/Detectors/Upgrades/ALICE3/FT3/simulation/src/FT3SimulationLinkDef.h +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license 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. - -#ifdef __CLING__ - -#pragma link off all globals; -#pragma link off all classes; -#pragma link off all functions; - -#pragma link C++ class o2::ft3::FT3Layer + ; -#pragma link C++ class o2::ft3::Detector + ; -#pragma link C++ class o2::base::DetImpl < o2::ft3::Detector> + ; - -#endif diff --git a/Detectors/Upgrades/ALICE3/README.md b/Detectors/Upgrades/ALICE3/README.md index 6ff034facb546..f491ae316e046 100644 --- a/Detectors/Upgrades/ALICE3/README.md +++ b/Detectors/Upgrades/ALICE3/README.md @@ -25,7 +25,7 @@ A list of the available DetIDs is reproted in the table below: | `A3IP` | Beam pipe | | `TRK` | Barrel Tracker | | `TF3` | Time Of Flight detectors | -| `FT3` | Forward endcaps | +| `FT3` | Obsolete: Forward endcaps are included in TRK | | `RCH` | Ring Imaging Cherenkov detectors | | `ECL` | Electromagnetic Calorimeter | | `MI3` | Muon Identification | @@ -69,21 +69,20 @@ Configurables for various sub-detectors are presented in the following Table: | Available options | Link to options | | ----------------- | ---------------------------------------------------------------- | | TRK | [Link to TRK options](./TRK/README.md#specific-detector-setup) | -| FT3 | [Link to FT3 options](./FT3/README.md#specific-detector-setup) | | TOF | [Link to TOF options](./IOTOF/README.md#specific-detector-setup) | Example O2 command to create a geometry with **segmented layers for TRK (expect for VD), FT3 and TOF:** ```bash -o2-sim-serial-run5 -n 1 -g pythia8hi -m A3IP TRK FT3 TF3 \ ---configKeyValues "TRKBase.layoutVD=kIRISFullCyl;TRKBase.layoutMLOT=kSegmented;FT3Base.layoutFT3=kSegmented;IOTOFBase.segmentedInnerTOF=true;IOTOFBase.segmentedOuterTOF=true" +o2-sim-serial-run5 -n 1 -g pythia8hi -m A3IP TRK TF3 \ +--configKeyValues "TRKBase.layoutVD=kIRISFullCyl;TRKBase.layoutMLOT=kSegmented;TRKBase.layoutFT3=kSegmentedFT3;IOTOFBase.segmentedInnerTOF=true;IOTOFBase.segmentedOuterTOF=true" ``` Example O2 command to create a geometry with **simple (non-segmented) layers for TRK, FT3 and TOF**: ```bash -o2-sim-serial-run5 -n 1 -g pythia8hi -m A3IP TRK FT3 TF3 \ ---configKeyValues "TRKBase.layoutVD=kIRISFullCyl;TRKBase.layoutMLOT=kCylindrical;FT3Base.layoutFT3=kTrapezoidal;IOTOFBase.segmentedInnerTOF=false;IOTOFBase.segmentedOuterTOF=false" +o2-sim-serial-run5 -n 1 -g pythia8hi -m A3IP TRK TF3 \ +--configKeyValues "TRKBase.layoutVD=kIRISFullCyl;TRKBase.layoutMLOT=kCylindrical;TRKBase.layoutFT3=kTrapezoidal;IOTOFBase.segmentedInnerTOF=false;IOTOFBase.segmentedOuterTOF=false" ``` ### Output of the simulation diff --git a/Detectors/Upgrades/ALICE3/TRK/README.md b/Detectors/Upgrades/ALICE3/TRK/README.md index efe07ab092eb2..b2880517a66c9 100644 --- a/Detectors/Upgrades/ALICE3/TRK/README.md +++ b/Detectors/Upgrades/ALICE3/TRK/README.md @@ -15,12 +15,16 @@ Configurables for various sub-detectors are presented in the following Table: | Subsystem | Available options | Comments | | ------------------ | ------------------------------------------------------- | ---------------------------------------------------------------- | | `TRKBase.layoutVD` | `kIRIS4` (default), `kIRISFullCyl`, `kIRIS5`, `kIRIS4a` | [link to definitions](./base/include/TRKBase/TRKBaseParam.h) | -| `TRKBase.layoutMLOT` | `kCylindrical`, `kSegmented` (default) | `kSegmented` produces a Turbo layout for ML and a Staggered layout for OT | +| `TRKBase.layoutMLOT` | `kCylindrical`, `kSegmented` (default) | `kSegmented` produces a Turbo layout for ML and a Staggered layout for OT | | `TRKBase.layoutSRV` | `kPeacockv1` (default), `kLOISymm` | `kLOISymm` produces radially symmetric service volumes, as used in the LoI | +| `TRKBase.disableFT3` | `false` (default), `true` | toggle to disable the forward disks | +| `TRKBase.layoutFT3` | `kSegmentedStave` (default), `kSegmentedFT3`, `kTrapezoidal` | disk geometry settings `kSegmentedFT3` refers to an outdated segmentation | +| `TRKBase.nTrapezoidalSegments` | integer; default: 32 | number of trapezoidal segments in the disks for kTrapezoidal layout | + For example, a geometry with fully cylindrical tracker barrel (for all layers in VD, ML and OT) can be obtained by ```bash -o2-sim-serial-run5 -n 1 -g pythia8hi -m A3IP TRK FT3 TF3 \ +o2-sim-serial-run5 -n 1 -g pythia8hi -m A3IP TRK TF3 \ --configKeyValues "TRKBase.layoutVD=kIRISFullCyl;TRKBase.layoutMLOT=kCylindrical" ``` @@ -89,5 +93,9 @@ From the 6th valid line onwards, lines are parsed as `TRKOTLayer` objects. These 80.0 0.01 0.0 56 22 1 ``` +## Additional options for forward disks + +Furthermore, there are more options in the case of stave segmentation -- for only OT or both. The user can set to cut the staves exactly on the nominal inner radii (true by default), and outer radii (false by default) of the disks. This exists since (planned) placements of sensors & staves often protrude out of the nominal radii to be more able to cover the nominal disk area. In addition, it is possible to draw reference circles (`TRKBase.drawReferenceCircles`) in root for the stave segmented layouts for both the inner (red) and outer (blue) radii. This is off by default, yet can be toggled if the user wants to see how tight the tiling is to the nominal radii -- for visualisation purposes only. + diff --git a/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/AlmiraParam.h b/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/AlmiraParam.h index 9929a14c4e39c..53d4792f7c2a5 100644 --- a/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/AlmiraParam.h +++ b/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/AlmiraParam.h @@ -25,7 +25,8 @@ namespace trk { struct AlmiraParam : public o2::conf::ConfigurableParamHelper { - static constexpr size_t kNLayers = constants::VD::petal::nLayers + constants::ML::nLayers + constants::OT::nLayers; + // This should be part of geometryTGeo + static constexpr size_t kNLayers = constants::VD::petal::nLayers + constants::ML::nLayers + constants::OT::nLayers + constants::MLOTDisks::nLayers; static constexpr size_t getNLayers() { return kNLayers; } int roFrameLengthInBCPerLayer[kNLayers] = {0}; ///< ROF length in BC per layer diff --git a/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/GeometryTGeo.h b/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/GeometryTGeo.h index 53ad7662cbfcd..f4a28f233ae9c 100644 --- a/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/GeometryTGeo.h +++ b/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/GeometryTGeo.h @@ -42,6 +42,13 @@ class GeometryTGeo : public o2::detectors::DetMatrixCache } return sInstance.get(); }; + + static const char* getFT3VolPattern() { return sFT3VolumeName.c_str(); } + static const char* getFT3InnerVolPattern() { return sFT3InnerVolumeName.c_str(); } + static const char* getFT3LayerPattern() { return sFT3LayerName.c_str(); } + static const char* getFT3ChipPattern() { return sFT3ChipName.c_str(); } + static const char* getFT3PassivePattern() { return sFT3PassiveName.c_str(); } + static const char* getFT3SensorPattern() { return sFT3SensorName.c_str(); } static const char* getTRKVolPattern() { return sVolumeName.c_str(); } static const char* getTRKServiceVolPattern() { return sServiceVolName.c_str(); } static const char* getTRKLayerPattern() { return sLayerName.c_str(); } @@ -62,6 +69,7 @@ class GeometryTGeo : public o2::detectors::DetMatrixCache int getNumberOfChips() const { return mSize; } /// Determines the number of active parts in the Geometry + int extractNumberOfDisksMLOT(int dir) const; int extractNumberOfLayersMLOT(); int extractNumberOfLayersVD() const; int extractNumberOfPetalsVD() const; @@ -74,12 +82,15 @@ class GeometryTGeo : public o2::detectors::DetMatrixCache int extractNumberOfChipsMLOT(int lay) const; /// Extract number following the prefix in the name string + void extractChipIdsFT3(std::string const volName, int& layer, int& stave, int& chip) const; int extractVolumeCopy(const char* name, const char* prefix) const; int getNumberOfLayersMLOT() const { return mNumberOfLayersMLOT; } int getNumberOfActivePartsVD() const { return mNumberOfActivePartsVD; } int getNumberOfHalfStaves(int lay) const { return mNumberOfHalfStaves[lay]; } + int getNumberOfDisksMLOT() const { return mNumberOfDisksMLOT; } + int getNumberOfStavesInDisk(int lay) const { return mFirstStaveIndexDisc[lay + 1] - mFirstStaveIndexDisc[lay]; } bool isOwner() const { return mOwner; } void setOwner(bool v) { mOwner = v; } @@ -133,9 +144,10 @@ class GeometryTGeo : public o2::detectors::DetMatrixCache /// This routine computes the chip index number from the subDetID, petal, disk, layer, stave /// TODO: retrieve also from chip when chips will be available /// This routine computes the chip index number from the subDetID, petal, disk, layer, stave, half stave, module, chip + /// The subdetectors are numbers as follows: 0: VD; 1: ML+OT barrels; 2: ML+OT discs /// \param int subDetID The subdetector ID, 0 for VD, 1 for MLOT /// \param int petalcase The petal case number for VD, from 0 to 3 - /// \param int disk The disk number for VD, from 0 to 5 + /// \param int disk The disk number for VD or OT (VD 0-6 if present; OT 0-12 (18 for V1 geometry) /// \param int lay The layer number. Starting from 0 both for VD and MLOT /// \param int stave The stave number for MLOT. Starting from 0 /// \param int halfstave The half stave number for MLOT. Can be 0 or 1 @@ -173,6 +185,8 @@ class GeometryTGeo : public o2::detectors::DetMatrixCache return (petalcase == 0) ? 0 : mLastChipIndexVD[petalcase - 1] + 1; } else if (subDetID == 1) { // MLOT return mLastChipIndex[lay + mNumberOfPetalsVD - 1] + 1; + } else if (subDetID == 2) { + return mFirstChipIndexMLOTDisc[lay]; } return -1; // not found } @@ -191,13 +205,14 @@ class GeometryTGeo : public o2::detectors::DetMatrixCache #endif static const char* composeSymNameLayer(int d, int layer); + static const char* composeSymNameLayerFT3(int dir, int layer); static const char* composeSymNameStave(int d, int layer); static const char* composeSymNameModule(int d, int layer); static const char* composeSymNameChip(int d, int layer); static const char* composeSymNameSensor(int d, int layer); protected: - static constexpr int MAXLAYERS = 20; ///< max number of active layers + static constexpr int MAXLAYERS = 25; ///< max number of active layers static std::string sVolumeName; static std::string sServiceVolName; @@ -216,26 +231,38 @@ class GeometryTGeo : public o2::detectors::DetMatrixCache static std::string sWrapperVolumeName; ///< Wrapper volume name, not implemented at the moment + static std::string sFT3InnerVolumeName; ///< Mother inner volume name + static std::string sFT3VolumeName; ///< Mother volume name + static std::string sFT3LayerName; ///< Layer name + static std::string sFT3ChipName; ///< Chip name + static std::string sFT3PassiveName; ///< Passive material name + static std::string sFT3SensorName; ///< Sensor name + Int_t mNumberOfLayersMLOT; ///< number of layers + Int_t mNumberOfDisksMLOT; ///< number of ML/OT disks (12 for v3) Int_t mNumberOfActivePartsVD; ///< number of layers Int_t mNumberOfLayersVD; ///< number of layers Int_t mNumberOfPetalsVD; ///< number of Petals = chip in each VD layer Int_t mNumberOfDisksVD; ///< number of Disks = 6 - std::vector mNumberOfStaves; ///< Number Of Staves per layer in ML/OT + std::vector mNumberOfStaves; ///< Number Of Staves per layer in ML/OT barrels + std::vector mNumberOfStavesMLOTDDiscs; ///< Number Of Staves per layer in ML/OT discs std::vector mNumberOfHalfStaves; ///< Number Of Half staves in each stave of the layer in ML/OT std::vector mNumberOfModules; ///< Number Of Modules per stave (half stave) in ML/OT std::vector mNumberOfChips; ///< number of chips per module in ML/OT std::vector mNumberOfChipsPerLayerVD; ///< number of chips per layer VD ( = number of petals) std::vector mNumberOfChipsPerLayerMLOT; ///< number of chips per layer MLOT + std::vector mNumberOfChipPerDiskMLOT; ///< number of chips per disc in MLOT std::vector mNumbersOfChipPerDiskVD; ///< numbersOfChipPerDiskVD std::vector mNumberOfChipsPerPetalVD; ///< numbersOfChipPerPetalVD // std::vector mNumberOfChipsPerStave; ///< number of chips per stave in ML/OT // std::vector mNumberOfChipsPerHalfStave; ///< number of chips per half stave in ML/OT // std::vector mNumberOfChipsPerModule; ///< number of chips per module in ML/OT - std::vector mLastChipIndex; ///< max ID of the detctor in the petal(VD) or layer(MLOT) - std::vector mLastChipIndexVD; ///< max ID of the detctor in the layer for the VD - std::vector mLastChipIndexMLOT; ///< max ID of the detctor in the layer for the MLOT - + std::vector mLastChipIndex; ///< max ID of the detector in the petal(VD) or layer(MLOT) + std::vector mLastChipIndexVD; ///< max ID of the detector in the layer for the VD + // std::vector mLastChipIndexMLOT; ///< max ID of the detector in the layer for the MLOT + std::vector mFirstChipIndexMLOTDisc; ///< ID of the first sensor chip in the layer for the MLOT; array size is one larger than the number of disks; last element equals nChips+1 + std::vector mFirstStaveIndexDisc; ///< Index of first stave (abs ID) in each MLOT Disc + std::vector mFirstChipIndexStave; ///< Index of first chip on stave (Discs) std::array mLayerToWrapper; ///< Layer to wrapper correspondence, not implemented yet bool mOwner = true; //! is it owned by the singleton? diff --git a/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/SegmentationChip.h b/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/SegmentationChip.h index 7ee569c9bd8e8..fac5198966fd6 100644 --- a/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/SegmentationChip.h +++ b/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/SegmentationChip.h @@ -116,7 +116,7 @@ class SegmentationChip maxWidth = constants::VD::petal::layer::width[layer]; maxLength = constants::VD::petal::layer::length; // TODO: change this to use the layer and disk - } else if (subDetID == 1) { + } else if (subDetID == 1 || subDetID == 2) { pitchRow = PitchRowMLOT; pitchCol = PitchColMLOT; maxWidth = constants::moduleMLOT::chip::width - constants::moduleMLOT::chip::passiveEdgeReadOut; @@ -135,7 +135,7 @@ class SegmentationChip maxWidth = constants::VD::petal::layer::width[layer]; maxLength = constants::VD::petal::layer::length; // TODO: change this to use the layer and disk - } else if (subDetID == 1) { // ML/OT + } else if (subDetID == 1 || subDetID == 2) { // ML/OT maxWidth = constants::moduleMLOT::chip::width - constants::moduleMLOT::chip::passiveEdgeReadOut; maxLength = constants::moduleMLOT::chip::length; } @@ -151,7 +151,7 @@ class SegmentationChip nRows = constants::VD::petal::layer::nRows[layer]; nCols = constants::VD::petal::layer::nCols; // TODO: change this to use the layer and disk - } else if (subDetID == 1) { + } else if (subDetID == 1 || subDetID == 2) { nRows = constants::moduleMLOT::chip::nRows; nCols = constants::moduleMLOT::chip::nCols; } @@ -196,7 +196,7 @@ class SegmentationChip if (subDetID == 0) { xRow = 0.5 * (constants::VD::petal::layer::width[layer] - PitchRowVD) - (row * PitchRowVD); zCol = col * PitchColVD + 0.5 * (PitchColVD - constants::VD::petal::layer::length); - } else if (subDetID == 1) { // ML/OT + } else if (subDetID == 1 || subDetID == 2) { // ML/OT xRow = 0.5 * (constants::moduleMLOT::chip::width - constants::moduleMLOT::chip::passiveEdgeReadOut - PitchRowMLOT) - (row * PitchRowMLOT); zCol = col * PitchColMLOT + 0.5 * (PitchColMLOT - constants::moduleMLOT::chip::length); } diff --git a/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/Specs.h b/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/Specs.h index b484e13f3546e..be6d5c8808275 100644 --- a/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/Specs.h +++ b/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/Specs.h @@ -142,6 +142,12 @@ constexpr double pitchZ{10.0 * mu}; constexpr double responseYShift{5 * mu}; /// center of the epitaxial layer constexpr double thickness{20 * mu}; } // namespace alice3resp + +namespace MLOTDisks +{ +constexpr int nLayers{12}; // number of disks in the ML and OT +} + } // namespace o2::trk::constants #endif diff --git a/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/TRKBaseParam.h b/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/TRKBaseParam.h index 65194ad6edfcb..7a9f0b5dbb769 100644 --- a/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/TRKBaseParam.h +++ b/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/TRKBaseParam.h @@ -32,6 +32,13 @@ enum eMLOTLayout { kSegmented, }; +enum eFT3Layout { + kTrapezoidal = 0, + kSegmentedFT3, + kSegmentedStave, + kSegmentedStaveOTOnly // TODO: remove this? +}; + enum eSrvLayout { kPeacockv1 = 0, kLOISymm, @@ -43,12 +50,30 @@ struct TRKBaseParam : public o2::conf::ConfigurableParamHelper { bool irisOpen = false; bool includeLowServices = false; + bool disableFT3 = false; + + // Options for forward disks (FT3) + int nTrapezoidalSegments = 32; // for the simple trapezoidal disks + // Forward discs: define tolerance allowed for staves to go outside nominal radii + double staveTolFT3MLInner = 0.; + double staveTolFT3MLOuter = 0.; + double staveTolFT3OTInner = 0.; + double staveTolFT3OTOuter = 0.; + + // Forward discs: toggle to center staves at x=0 line + bool placeSensorStackInMiddleOfStave = false; + + // Draw reference circles at inner and outer radius of forward discs for visualisation + bool drawReferenceCircles = false; + eVDLayout layoutVD = kIRIS4; // VD detector layout design eMLOTLayout layoutMLOT = kSegmented; // ML and OT detector layout design + eFT3Layout layoutFT3 = kSegmentedStave; eSrvLayout layoutSRV = kPeacockv1; // Layout of services eVDLayout getLayoutVD() const { return layoutVD; } eMLOTLayout getLayoutMLOT() const { return layoutMLOT; } + eFT3Layout getLayoutFT3() const { return layoutFT3; } eSrvLayout getLayoutSRV() const { return layoutSRV; } O2ParamDef(TRKBaseParam, "TRKBase"); diff --git a/Detectors/Upgrades/ALICE3/TRK/base/src/GeometryTGeo.cxx b/Detectors/Upgrades/ALICE3/TRK/base/src/GeometryTGeo.cxx index ddfc844cc964d..1ad0552aa768c 100644 --- a/Detectors/Upgrades/ALICE3/TRK/base/src/GeometryTGeo.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/base/src/GeometryTGeo.cxx @@ -43,6 +43,15 @@ std::string GeometryTGeo::sMetalStackName = "TRKMetalStack"; std::string GeometryTGeo::sWrapperVolumeName = "TRKUWrapVol"; ///< Wrapper volume name, not implemented at the moment +std::string GeometryTGeo::sFT3VolumeName = "FT3V"; ///< Mother volume name +std::string GeometryTGeo::sFT3InnerVolumeName = "FT3Inner"; ///< Mother inner volume name +std::string GeometryTGeo::sFT3LayerName = "FT3Layer"; ///< Layer name +// TODO: chip and passive are only used by trapezoidal geom; use same for all? +std::string GeometryTGeo::sFT3ChipName = "FT3Chip"; ///< Chip name +std::string GeometryTGeo::sFT3PassiveName = "Passive"; ///< Passive material name +// TODO: this is now only used for the not-segmented version; synchronise? +std::string GeometryTGeo::sFT3SensorName = "FT3Sensor"; ///< Sensor name + o2::trk::GeometryTGeo::~GeometryTGeo() { if (!mOwner) { @@ -87,6 +96,7 @@ void GeometryTGeo::Build(int loadTrans) mNumberOfActivePartsVD = extractNumberOfActivePartsVD(); mNumberOfLayersVD = extractNumberOfLayersVD(); mNumberOfDisksVD = extractNumberOfDisksVD(); + mNumberOfDisksMLOT = extractNumberOfDisksMLOT(0) + extractNumberOfDisksMLOT(1); mNumberOfStaves.resize(mNumberOfLayersMLOT); mNumberOfHalfStaves.resize(mNumberOfLayersMLOT); @@ -100,7 +110,7 @@ void GeometryTGeo::Build(int loadTrans) mLastChipIndex.resize(mNumberOfPetalsVD + mNumberOfLayersMLOT); mLastChipIndexVD.resize(mNumberOfPetalsVD); - mLastChipIndexMLOT.resize(mNumberOfLayersMLOT); /// ML and OT are part of TRK as the same detector, without disks + // mLastChipIndexMLOT.resize(mNumberOfLayersMLOT); /// ML and OT are part of TRK as the same detector, without disks for (int i = 0; i < mNumberOfLayersMLOT; i++) { if (mLayoutMLOT == eMLOTLayout::kCylindrical) { @@ -131,22 +141,98 @@ void GeometryTGeo::Build(int loadTrans) mNumberOfChipsPerLayerMLOT[i] = mNumberOfStaves[i] * mNumberOfHalfStaves[i] * mNumberOfModules[i] * mNumberOfChips[i]; numberOfChipsTotal += mNumberOfChipsPerLayerMLOT[i]; mLastChipIndex[i + mNumberOfPetalsVD] = numberOfChipsTotal - 1; - mLastChipIndexMLOT[i] = numberOfChipsTotal - 1; } + // Forward discs (FT3) part + int totDiscs = 0; + int absStaveIdx = 0; + + if (mFirstChipIndexStave.size() == 0) { + mFirstChipIndexStave.push_back(numberOfChipsTotal); + mFirstChipIndexMLOTDisc.push_back(numberOfChipsTotal); + } + if (mFirstStaveIndexDisc.size() == 0) { + mFirstStaveIndexDisc.push_back(0); + } + std::vector numberOfDiscs; + for (int iDir = 0; iDir < 2; iDir++) { + numberOfDiscs.push_back(extractNumberOfDisksMLOT(iDir)); + totDiscs += numberOfDiscs[iDir]; + LOG(debug) << "direction " << iDir << "; disk total " << totDiscs; + + for (int iDisc = 0; iDisc < numberOfDiscs[iDir]; iDisc++) { + TGeoVolume* trkV = gGeoManager->GetVolume(getTRKVolPattern()); + if (trkV == nullptr) { + LOG(fatal) << getName() << " volume " << getTRKVolPattern() << " is not in the geometry"; + } + auto layerNode = trkV->GetNode(Form("%s_1", composeSymNameLayerFT3(iDir, iDisc))); + if (layerNode == nullptr) { + LOG(info) << "Could not find layer node " << Form("%s_1", composeSymNameLayerFT3(iDir, iDisc)); + continue; + } + auto layerVol = layerNode->GetVolume(); + if (layerVol == nullptr) + LOG(fatal) << "Could not find layer volume " << Form("%s_1", composeSymNameLayerFT3(iDir, iDisc)); + TObjArray* nodes = layerVol->GetNodes(); + int nNodes = nodes->GetEntriesFast(); + int nStaves = 0; + int nSensor = 0; + std::vector chipsPerStave; + for (int j = 0; j < nNodes; j++) { + auto nd = dynamic_cast(nodes->At(j)); + const char* name = nd->GetName(); + if (strstr(name, "FT3Sensor") != nullptr && strstr(name, "Inactive") == nullptr) { + int direction = 0, layer = 0; + int stave = 0, chip = 0; + extractChipIdsFT3(name, layer, stave, chip); + if (stave >= chipsPerStave.size()) { + chipsPerStave.resize(stave + 1, 0); + nStaves = stave + 1; + } + // if (chip + 1 > mChipStaveIds.size()) mChipStaveIds.resize(chip+1); + if (chip + 1 >= chipsPerStave[stave]) { + chipsPerStave[stave] = chip + 1; + } + nSensor++; + } + } + LOG(debug) << "direction " << iDir << " disc " << iDisc << " has " << nNodes << " nodes of which " << nSensor << " sensors in " << chipsPerStave.size() << " staves"; + + if (nStaves != chipsPerStave.size()) { + LOG(info) << "Inconsistency in stave count " << nStaves << " " << chipsPerStave.size(); + } + mFirstChipIndexStave.resize(absStaveIdx + chipsPerStave.size() + 1, -1); + for (int nChips : chipsPerStave) { + LOG(debug) << "Absolute Stave ID " << absStaveIdx << " : " << nChips << " sensors, setting first chip ID for next stave to " << mFirstChipIndexStave[absStaveIdx] + nChips; + numberOfChipsTotal += nChips; + mFirstChipIndexStave[absStaveIdx + 1] = mFirstChipIndexStave[absStaveIdx] + nChips; + absStaveIdx++; + } + mFirstStaveIndexDisc.push_back(absStaveIdx); + mFirstChipIndexMLOTDisc.push_back(numberOfChipsTotal); + LOG(debug) << "Total sensors so far " << numberOfChipsTotal; + } + } setSize(numberOfChipsTotal); + if (numberOfChipsTotal > std::numeric_limits::max()) { + LOG(fatal) << "Too many sensor chips in TRK: " << numberOfChipsTotal; + } + // TODO: add corresponding info for FT3 defineMLOTSensors(); fillTrackingFramesCacheMLOT(); fillMatrixCache(loadTrans); + LOG(info) << "Build done"; } //__________________________________________________________________________ int GeometryTGeo::getSubDetID(int index) const { - if (index <= mLastChipIndexVD[mLastChipIndexVD.size() - 1]) { + if (index >= 0 && index <= mLastChipIndexVD[mLastChipIndexVD.size() - 1]) { return 0; - } else if (index > mLastChipIndexVD[mLastChipIndexVD.size() - 1]) { + } else if (index <= mLastChipIndex[mLastChipIndex.size() - 1]) { return 1; + } else if (index < mFirstChipIndexMLOTDisc[mFirstChipIndexMLOTDisc.size() - 1]) { + return 2; } return -1; /// not found } @@ -187,10 +273,10 @@ int GeometryTGeo::getDisk(int index) const int GeometryTGeo::getLayer(int index) const { int subDetID = getSubDetID(index); - int petalcase = getPetalCase(index); int lay = 0; if (subDetID == 0) { /// VD + int petalcase = getPetalCase(index); if (index % mNumberOfChipsPerPetalVD[petalcase] >= mNumberOfLayersVD) { return -1; /// disks } @@ -200,6 +286,12 @@ int GeometryTGeo::getLayer(int index) const lay++; } return lay - mNumberOfPetalsVD; /// numeration of MLOT layers starting from 0 + } else if (subDetID == 2) { + lay = mNumberOfDisksMLOT - 1; + while (index < mFirstChipIndexMLOTDisc[lay] && lay > 0) { + lay--; + } + return lay; } return -1; /// -1 if not found } @@ -210,7 +302,18 @@ int GeometryTGeo::getLayerTRK(int index) const return -1; /// disks do not have a global layer index } int subDetID = getSubDetID(index); - return subDetID * o2::trk::constants::VD::petal::nLayers + getLayer(index); // MLOT: offset by number of VD layers + int firstDetLayer = 0; + + // NOTE: taking these from o2::trk::constants, instead + // of the geometry that is constructed in the 'Build' function + // risks inconsistencies... + + if (subDetID == 1) { + firstDetLayer = o2::trk::constants::VD::petal::nLayers; + } else if (subDetID == 2) { + firstDetLayer = o2::trk::constants::VD::petal::nLayers + o2::trk::constants::ML::nLayers + o2::trk::constants::OT::nLayers; + } + return firstDetLayer + getLayer(index); } //__________________________________________________________________________ int GeometryTGeo::getStave(int index) const @@ -239,6 +342,13 @@ int GeometryTGeo::getStave(int index) const int chipsPerStave = Nmod * chipsPerModule; return index / chipsPerStave; } + } else if (subDetID == 2) { // Disks FT3 + int lay = getLayer(index); + int absStave = mFirstStaveIndexDisc[lay]; + while (index >= mFirstChipIndexStave[absStave] && absStave < mFirstStaveIndexDisc[lay + 1]) { + absStave++; + } + return absStave - 1 - mFirstStaveIndexDisc[lay]; } return -1; } @@ -326,6 +436,10 @@ int GeometryTGeo::getChip(int index) const int chipsPerModule = Nchip; return index % chipsPerModule; } + } else if (subDetID == 2) { // Forward disks (FT3) + int lay = getLayer(index); + int stave = getStave(index); + return index - mFirstChipIndexStave[mFirstStaveIndexDisc[lay] + stave]; } return -1; } @@ -356,7 +470,7 @@ unsigned short GeometryTGeo::getChipIndex(int subDetID, int petalcase, int disk, } } - LOGP(warning, "Chip index not found for subDetID %d, petalcase %d, disk %d, layer %d, stave %d, halfstave %d, module %d, chip %d, returning numeric limit", subDetID, petalcase, disk, lay, stave, halfstave, mod, chip); + LOGP(warning, "Chip index not found for subDetID {}, petalcase {}, disk {}, layer {}, stave {}, halfstave {}, module {}, chip {}, returning numeric limit", subDetID, petalcase, disk, lay, stave, halfstave, mod, chip); return std::numeric_limits::max(); // not found } @@ -381,9 +495,12 @@ unsigned short GeometryTGeo::getChipIndex(int subDetID, int volume, int lay, int int chipsPerStave = Nmod * chipsPerModule; return getFirstChipIndex(lay, -1, subDetID) + stave * chipsPerStave + mod * chipsPerModule + chip; } + } else if (subDetID == 2) { // FT3 + if (lay < mFirstStaveIndexDisc.size() && mFirstStaveIndexDisc[lay] + stave < mFirstChipIndexStave.size()) { + return mFirstChipIndexStave[mFirstStaveIndexDisc[lay] + stave] + chip; + } } - - LOGP(warning, "Chip index not found for subDetID %d, volume %d, layer %d, stave %d, halfstave %d, module %d, chip %d, returning numeric limit", subDetID, volume, lay, stave, halfstave, mod, chip); + LOGP(warning, "Chip index not found for subDetID {}, volume {}, layer {}, stave {}, halfstave {}, module {}, chip {}, returning numeric limit", subDetID, volume, lay, stave, halfstave, mod, chip); return std::numeric_limits::max(); // not found } @@ -445,6 +562,14 @@ TString GeometryTGeo::getMatrixPath(int index) const path += Form("%s%d_%d/", getTRKChipPattern(), layer, chip); // TRKChipx_y path += Form("%s%d_1/", getTRKSensorPattern(), layer); // TRKSensorx_1 } + } else if (subDetID == 2) { + int direction = 0; + if (layer >= mNumberOfDisksMLOT / 2) { + direction = 1; + layer -= mNumberOfDisksMLOT / 2; + } + path += Form("%s%d_%d_1/", getFT3LayerPattern(), direction, layer); + path += Form("FT3Sensor_Active_%d_%d_%d_%d_%d", direction, layer, stave, chip, chip); } return path; } @@ -498,10 +623,9 @@ TGeoHMatrix* GeometryTGeo::extractMatrixSensor(int index) const void GeometryTGeo::defineMLOTSensors() { for (int i = 0; i < mSize; i++) { - if (getSubDetID(i) == 0) { - continue; + if (getSubDetID(i) == 1) { + sensorsMLOT.push_back(i); // TODO: this is now a trivial array where each element is a sequence number (expect that the first elements are skipped) } - sensorsMLOT.push_back(i); } } @@ -509,14 +633,20 @@ void GeometryTGeo::defineMLOTSensors() void GeometryTGeo::fillTrackingFramesCacheMLOT() { // fill for every sensor of ML & OT its tracking frame parameters + int nSensMLOT = sensorsMLOT.size(); + int nSensMLOTDisk = mFirstChipIndexMLOTDisc[mFirstChipIndexMLOTDisc.size() - 1] - mFirstChipIndexMLOTDisc[0]; if (!isTrackingFrameCachedMLOT() && !sensorsMLOT.empty()) { - size_t newSize = sensorsMLOT.size(); + size_t newSize = nSensMLOT + nSensMLOTDisk; mCacheRefXMLOT.resize(newSize); mCacheRefAlphaMLOT.resize(newSize); - for (int i = 0; i < newSize; i++) { + for (int i = 0; i < nSensMLOT; i++) { int sensorId = sensorsMLOT[i]; extractSensorXAlphaMLOT(sensorId, mCacheRefXMLOT[i], mCacheRefAlphaMLOT[i]); } + for (int i = nSensMLOT; i < newSize; i++) { + // LOG(info) << "Getting XAlpha for disk chip " << mFirstChipIndexMLOTDisc[0] + i; + extractSensorXAlphaMLOT(mFirstChipIndexMLOTDisc[0] + i, mCacheRefXMLOT[i], mCacheRefAlphaMLOT[i]); + } } } @@ -567,8 +697,14 @@ const char* GeometryTGeo::composeSymNameLayer(int d, int layer) { return Form("%s/%s%d", composeSymNameTRK(d), getTRKLayerPattern(), layer); } + #endif +const char* GeometryTGeo::composeSymNameLayerFT3(int dir, int layer) +{ + return Form("%s%d_%d", GeometryTGeo::getFT3LayerPattern(), dir, layer); +} + const char* GeometryTGeo::composeSymNameStave(int d, int layer) { return Form("%s/%s%d", composeSymNameLayer(d, layer), getTRKStavePattern(), layer); @@ -589,6 +725,37 @@ const char* GeometryTGeo::composeSymNameSensor(int d, int layer) return Form("%s/%s%d", composeSymNameChip(d, layer), getTRKSensorPattern(), layer); } +//__________________________________________________________________________ +void GeometryTGeo::extractChipIdsFT3(std::string const volName, int& layer, int& stave, int& chip) const +{ + if (volName.find("FT3Sensor_Active") == 0) { + int idx = volName.find('_') + 1; + idx = volName.find('_', idx) + 1; + int direction = std::stoi(volName.substr(idx)); + idx = volName.find('_', idx) + 1; + layer = std::stoi(volName.substr(idx)); + idx = volName.find('_', idx) + 1; + stave = std::stoi(volName.substr(idx)); + idx = volName.find('_', idx) + 1; + chip = std::stoi(volName.substr(idx)); + if (direction == 1) + layer += mNumberOfDisksMLOT / 2; + } else { + LOG(error) << "extractChipIdsFT3: Not a sensor volume " << volName; + layer = -1; + } +} + +//__________________________________________________________________________ +int GeometryTGeo::extractNumberOfDisksMLOT(int dir) const +{ + int numDiscs = 0; + while (gGeoManager->GetVolume(composeSymNameLayerFT3(dir, numDiscs))) { + numDiscs++; + } // Check maybe subvolume? + return numDiscs; // Assume same # layers on both sides +} + //__________________________________________________________________________ int GeometryTGeo::extractVolumeCopy(const char* name, const char* prefix) const { @@ -1160,6 +1327,7 @@ void GeometryTGeo::Print(Option_t*) const } LOGF(info, "Total number of chips: %d", getNumberOfChips()); + /* std::cout << "mLastChipIndex = ["; for (int i = 0; i < mLastChipIndex.size(); i++) { std::cout << mLastChipIndex[i]; @@ -1168,6 +1336,7 @@ void GeometryTGeo::Print(Option_t*) const } } std::cout << "]" << std::endl; + */ std::cout << "mLastChipIndexVD = ["; for (int i = 0; i < mLastChipIndexVD.size(); i++) { std::cout << mLastChipIndexVD[i]; diff --git a/Detectors/Upgrades/ALICE3/TRK/base/src/TRKBaseLinkDef.h b/Detectors/Upgrades/ALICE3/TRK/base/src/TRKBaseLinkDef.h index e36955cdd150d..7bddc1cddd37c 100644 --- a/Detectors/Upgrades/ALICE3/TRK/base/src/TRKBaseLinkDef.h +++ b/Detectors/Upgrades/ALICE3/TRK/base/src/TRKBaseLinkDef.h @@ -19,7 +19,7 @@ #pragma link C++ class o2::conf::ConfigurableParamHelper < o2::trk::TRKBaseParam> + ; #pragma link C++ class o2::trk::AlmiraParam + ; -#pragma link C++ class o2::trk::GeometryTGeo + +#pragma link C++ class o2::trk::GeometryTGeo; #pragma link C++ class o2::trk::TRKBaseParam + ; #pragma link C++ class o2::trk::SegmentationChip + ; diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/CMakeLists.txt b/Detectors/Upgrades/ALICE3/TRK/simulation/CMakeLists.txt index 6d30d8d01bb12..e8460abe71dc0 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/CMakeLists.txt +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/CMakeLists.txt @@ -17,12 +17,13 @@ o2_add_library(TRKSimulation src/Detector.cxx src/DigiParams.cxx src/Digitizer.cxx + src/FT3Layer.cxx + src/FT3Module.cxx src/TRKServices.cxx src/DPLDigitizerParam.cxx src/VDLayer.cxx src/VDGeometryBuilder.cxx PUBLIC_LINK_LIBRARIES O2::TRKBase - O2::FT3Simulation O2::ITSMFTSimulation O2::DetectorsRaw O2::SimulationDataFormat) @@ -34,6 +35,8 @@ o2_target_root_dictionary(TRKSimulation include/TRKSimulation/DigiParams.h include/TRKSimulation/Digitizer.h include/TRKSimulation/Detector.h + include/TRKSimulation/FT3Layer.h + include/TRKSimulation/FT3Module.h include/TRKSimulation/TRKLayer.h include/TRKSimulation/TRKServices.h include/TRKSimulation/VDLayer.h diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/Detector.h b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/Detector.h index 9666916800185..444905a1bf18a 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/Detector.h +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/Detector.h @@ -17,6 +17,7 @@ #include "TRKSimulation/TRKLayer.h" #include "TRKSimulation/TRKServices.h" +#include "TRKSimulation/FT3Layer.h" #include "TRKBase/GeometryTGeo.h" #include @@ -68,6 +69,7 @@ class Detector : public o2::base::DetImpl } void configMLOT(); + void configFT3ScopingV3(); void configFromFile(std::string fileName = "alice3_TRK_layout.txt"); void configToFile(std::string fileName = "alice3_TRK_layout.txt"); @@ -75,6 +77,9 @@ class Detector : public o2::base::DetImpl void createMaterials(); void createGeometry(); + static constexpr int kForward = 0; + static constexpr int kBackward = 1; + private: int mNumberOfVolumes; int mNumberOfVolumesVD; @@ -98,12 +103,21 @@ class Detector : public o2::base::DetImpl void defineSensitiveVolumes(); protected: + std::array, 2> mFT3LayerName; // Two sets of layer (disc) names, one per direction (forward/backward) std::vector mSensorID; //! layer identifiers std::vector mSensorName; //! layer names + std::array, 2> mFT3Layers; // Two sets of layers (discs), one per direction (forward/backward) public: static constexpr Int_t sNumberVDPetalCases = 4; //! Number of VD petals int getNumberOfLayers() const { return mLayers.size(); } //! Number of TRK layers + int getNumberOfFT3Layers() const + { + if (mFT3LayerName[kBackward].size() != mFT3LayerName[kForward].size()) { + LOG(fatal) << "Number of layers in the two directions are different! Returning 0."; + } + return mFT3LayerName[kBackward].size(); + } void Print(FairVolume* vol, int volume, int subDetID, int layer, int stave, int halfstave, int mod, int chip, int chipID) const; diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/Digitizer.h b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/Digitizer.h index 5910fc98134aa..69a73d3ab8319 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/Digitizer.h +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/Digitizer.h @@ -72,7 +72,11 @@ class Digitizer const o2::trk::DigiParams& getDigitParams() const { return mParams; } // provide the common trk::GeometryTGeo to access matrices and segmentation - void setGeometry(const o2::trk::GeometryTGeo* gm) { mGeometry = gm; } + void setGeometry(const o2::trk::GeometryTGeo* gm) + { + LOG(info) << "trk::Digizer set geom"; + mGeometry = gm; + } uint32_t getEventROFrameMin() const { return mEventROFrameMin; } uint32_t getEventROFrameMax() const { return mEventROFrameMax; } @@ -109,7 +113,7 @@ class Digitizer { if (subDetID == 0) { // VD return constants::VD::petal::layer::nCols; - } else if (subDetID == 1) { // ML/OT: the smallest element is a chip of 470 rows and 640 cols + } else if (subDetID == 1 || subDetID == 2) { // ML/OT: the smallest element is a chip of 470 rows and 640 cols return constants::moduleMLOT::chip::nCols; } return 0; @@ -123,7 +127,7 @@ class Digitizer { if (subDetID == 0) { // VD return constants::VD::petal::layer::nRows[layer]; - } else if (subDetID == 1) { // ML/OT + } else if (subDetID == 1 || subDetID == 2) { // ML/OT return constants::moduleMLOT::chip::nRows; } return 0; diff --git a/Detectors/Upgrades/ALICE3/FT3/simulation/include/FT3Simulation/FT3Layer.h b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/FT3Layer.h similarity index 92% rename from Detectors/Upgrades/ALICE3/FT3/simulation/include/FT3Simulation/FT3Layer.h rename to Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/FT3Layer.h index 282f8fd274ec0..5ccfc406009a1 100644 --- a/Detectors/Upgrades/ALICE3/FT3/simulation/include/FT3Simulation/FT3Layer.h +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/FT3Layer.h @@ -15,16 +15,15 @@ #ifndef ALICEO2_FT3_UPGRADEV3LAYER_H_ #define ALICEO2_FT3_UPGRADEV3LAYER_H_ -#include // for gGeoManager -#include "Rtypes.h" // for Double_t, Int_t, Bool_t, etc -#include "FT3Simulation/Detector.h" // for Detector, Detector::Model -#include "FT3Simulation/FT3Module.h" +#include // for gGeoManager +#include "Rtypes.h" // for Double_t, Int_t, Bool_t, etc +#include "TRKSimulation/FT3Module.h" class TGeoVolume; namespace o2 { -namespace ft3 +namespace trk { /// This class defines the Geometry for the FT3 Layer TGeo. This is a work class used @@ -92,7 +91,7 @@ class FT3Layer : public TObject ClassDefOverride(FT3Layer, 0); // ALICE 3 EndCaps geometry }; -} // namespace ft3 +} // namespace trk } // namespace o2 #endif diff --git a/Detectors/Upgrades/ALICE3/FT3/simulation/include/FT3Simulation/FT3Module.h b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/FT3Module.h similarity index 97% rename from Detectors/Upgrades/ALICE3/FT3/simulation/include/FT3Simulation/FT3Module.h rename to Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/FT3Module.h index 75c1cfb7210e3..f71bab0a1e882 100644 --- a/Detectors/Upgrades/ALICE3/FT3/simulation/include/FT3Simulation/FT3Module.h +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/FT3Module.h @@ -19,7 +19,7 @@ #include #include -#include "FT3Simulation/FT3ModuleConstants.h" +#include "TRKSimulation/FT3ModuleConstants.h" // define types for y positions, second element is the stack height using PositionType = std::pair; @@ -27,7 +27,7 @@ using PositionTypes = std::vector; using PosNegPositionTypes = std::pair; // define type of the y position range: First pair is (min, max) for positive y using PositionRangeType = std::pair, std::pair>; -namespace Constants = o2::ft3::ModuleConstants; +namespace Constants = o2::trk::FT3ModuleConstants; class FT3Module { diff --git a/Detectors/Upgrades/ALICE3/FT3/simulation/include/FT3Simulation/FT3ModuleConstants.h b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/FT3ModuleConstants.h similarity index 99% rename from Detectors/Upgrades/ALICE3/FT3/simulation/include/FT3Simulation/FT3ModuleConstants.h rename to Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/FT3ModuleConstants.h index 4f2bfce5c3f1d..9069e4cf906bd 100644 --- a/Detectors/Upgrades/ALICE3/FT3/simulation/include/FT3Simulation/FT3ModuleConstants.h +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/FT3ModuleConstants.h @@ -20,7 +20,7 @@ #include #include -namespace o2::ft3::ModuleConstants +namespace o2::trk::FT3ModuleConstants { /* CURRENT STATUS: * 25x29mm sensors, 2mm inactive on one side @@ -215,6 +215,6 @@ inline StaveConfig getStaveConfig(bool isInnerDisk) } } -} // namespace o2::ft3::ModuleConstants +} // namespace o2::trk::FT3ModuleConstants #endif // FT3MODULECONSTANTS_H \ No newline at end of file diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/src/Detector.cxx b/Detectors/Upgrades/ALICE3/TRK/simulation/src/Detector.cxx index 196727b2c140f..493b6b024f5c0 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/src/Detector.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/Detector.cxx @@ -57,6 +57,9 @@ Detector::Detector(bool active) configFromFile(trkPars.configFile); } else { configMLOT(); + if (!trkPars.disableFT3) { + configFT3ScopingV3(); + } configToFile(); configServices(); } @@ -132,6 +135,56 @@ void Detector::configMLOT() } } +void Detector::configFT3ScopingV3() +{ + // Build the FT3 detector according to v3 layout + // https://indico.cern.ch/event/1596309/contributions/6728167/attachments/3190117/5677220/2025-12-10-AW-ALICE3planning.pdf + // Middle disks inner radius 10 cm + // Outer disks inner radius 20 cm + + LOG(info) << "Building FT3 Detector: v3 scoping version"; + + const int numberOfLayers = 6; + const float sensorThickness = 30.e-4; + const float layersx2X0 = 1.e-2; + using LayerConfig = std::array; // {z_layer, r_in, r_out, Layerx2X0} + const std::array layersConfigCSide{LayerConfig{77., 10.0, 35., layersx2X0}, + LayerConfig{100., 10.0, 35., layersx2X0}, + LayerConfig{122., 10.0, 35., layersx2X0}, + LayerConfig{150., 20.0, 68.f, layersx2X0}, + LayerConfig{180., 20.0, 68.f, layersx2X0}, + LayerConfig{220., 20.0, 68.f, layersx2X0}}; + + const std::array layersConfigASide{LayerConfig{77., 10.0, 35., layersx2X0}, + LayerConfig{100., 10.0, 35., layersx2X0}, + LayerConfig{122., 10.0, 35., layersx2X0}, + LayerConfig{150., 20.0, 68.f, layersx2X0}, + LayerConfig{180., 20.0, 68.f, layersx2X0}, + LayerConfig{220., 20.0, 68.f, layersx2X0}}; + const std::array enabled{true, true, true, true, true, true}; // To enable or disable layers for debug purpose + + for (int direction : {kBackward, kForward}) { + mFT3LayerName[direction].clear(); + const std::array& layerConfig = (direction == kBackward) ? layersConfigCSide : layersConfigASide; + for (int layerNumber = 0; layerNumber < numberOfLayers; layerNumber++) { + if (!enabled[layerNumber]) { + continue; + } + const std::string directionName = std::to_string(direction); + const std::string layerName = GeometryTGeo::getFT3LayerPattern() + directionName + std::string("_") + std::to_string(layerNumber); + mFT3LayerName[direction].push_back(layerName.c_str()); + const float z = layerConfig[layerNumber][0]; + const float rIn = layerConfig[layerNumber][1]; + const float rOut = layerConfig[layerNumber][2]; + const float x0 = layerConfig[layerNumber][3]; + LOG(info) << "buildFT3ScopingV3 -> Adding Layer " << layerNumber << "/" << numberOfLayers << " " << layerName << " at z = " << z; + // Add layers + const bool isMiddleLayer = layerNumber < 3; + auto& thisLayer = mFT3Layers[direction].emplace_back(direction, layerNumber, layerName, z, rIn, rOut, x0, isMiddleLayer); + } + } +} + void Detector::configFromFile(std::string fileName) { // Override the default geometry if config file provided @@ -377,6 +430,40 @@ void Detector::createGeometry() mServices.excavateFromVacuum("IRIS_CUTOUTsh"); mServices.registerVacuum(vTRK); + + // Place forward tracking discs + + TGeoVolume* A3IPvac = gGeoManager->GetVolume("OUT_PIPEVACUUM"); + if (!A3IPvac) { + LOG(info) << "Running simulation with no beam pipe."; + } + + // TODO: disambiquate layer/disk below + // This will need to adapt to the new scheme + if (!A3IPvac) { + for (int direction : {kBackward, kForward}) { // Backward layers at mLayers[0]; Forward layers at mLayers[1] + const std::string directionString = direction ? "Forward" : "Backward"; + LOG(info) << " Creating FT3 without beampipe " << directionString << " layers:"; + for (int iLayer = 0; iLayer < mFT3Layers[direction].size(); iLayer++) { + mFT3Layers[direction][iLayer].createLayer(vTRK); + } + } + } else { // If beampipe is enabled append inner disks to beampipe filling volume, this should be temporary. + TGeoVolume* volIFT3 = new TGeoVolumeAssembly(GeometryTGeo::getFT3InnerVolPattern()); + for (int direction : {kBackward, kForward}) { + const std::string directionString = direction ? "Forward" : "Backward"; + LOG(info) << " Creating FT3 " << directionString << " layers:"; + for (int iLayer = 0; iLayer < mFT3Layers[direction].size(); iLayer++) { + LOG(info) << " Creating " << directionString << " layer " << iLayer; + if (mFT3Layers[direction][iLayer].getIsInMiddleLayer()) { // ML disks + mFT3Layers[direction][iLayer].createLayer(volIFT3); + } else { + mFT3Layers[direction][iLayer].createLayer(vTRK); + } + } + } + A3IPvac->AddNode(volIFT3, 2, new TGeoTranslation(0., 0., 0.)); + } } void Detector::InitializeO2Detector() @@ -426,6 +513,69 @@ void Detector::defineSensitiveVolumes() LOGP(info, "Adding TRK Sensitive Volume {}", v->GetName()); AddSensitiveVolume(v); } + + // Add FT3 sensitive volumes + // TODO: do we need to loop over all volumes in our code, or can we use the geomanager? + // Get the flat list of ALL volumes present in the geometry + TObjArray* allVolumes = geoManager->GetListOfVolumes(); + int nVolumes = allVolumes->GetEntriesFast(); + + LOG(info) << "Adding FT3 Sensitive Volumes by iterating over all geometry volumes..."; + + for (int direction : {kBackward, kForward}) { + for (int iLayer = 0; iLayer < getNumberOfFT3Layers(); iLayer++) { + int iSens = 0; + + // Build the "signatures" (prefixes) of the names for the various layouts for this specific layer and direction: + + // 1. Trapezoidal/Cylindrical (format: FT3Sensor__) + std::string sig1 = Form("%s_%d_%d", GeometryTGeo::getFT3SensorPattern(), direction, iLayer); + + // 2. Segmented front/back (format: FT3Sensor_front___...) + std::string sig2 = "FT3Sensor_front_" + std::to_string(iLayer) + "_" + std::to_string(direction); + std::string sig3 = "FT3Sensor_back_" + std::to_string(iLayer) + "_" + std::to_string(direction); + + // 3. SegmentedStave (format: FT3Sensor___...) + // Add the trailing underscore to avoid confusing it with sig1 + std::string sig4 = "FT3Sensor_Active_" + std::to_string(direction) + "_" + std::to_string(iLayer) + "_"; + + // Iterate over all existing volumes to find matches + for (int i = 0; i < nVolumes; ++i) { + TGeoVolume* v = (TGeoVolume*)allVolumes->At(i); + std::string vName = v->GetName(); + + // Explicitly exclude the inactive silicon regions created in FT3Module + if (vName.find("Inactive") != std::string::npos || vName.find("inactive") != std::string::npos) { + continue; + } + + // Check if the volume name matches one of our active sensors + bool isMatch = false; + if (vName == sig1) { + isMatch = true; // Exact match for Trapezoidal/Cylindrical layouts + } else if (vName.find(sig2) == 0 || vName.find(sig3) == 0 || vName.find(sig4) == 0) { + isMatch = true; // Prefix match for Segmented and SegmentedStave layouts + } + + if (isMatch) { + AddSensitiveVolume(v); + /* + int volID = gMC ? TVirtualMC::GetMC()->VolId(vName.c_str()) : 0; + if (volID > 0) { + mActiveSensorMap[volID] = iLayer; + } + */ + iSens++; + } + } + + if (iSens == 0) { + LOG(error) << "NO sensitive volume found for FT3 direction " << direction << ", layer " << iLayer; + } else { + LOG(info) << iSens << " sensitive volume(s) added for FT3 direction " << direction << " layer " << iLayer; + } + } + } } void Detector::EndOfEvent() { Reset(); } @@ -477,10 +627,6 @@ bool Detector::ProcessHits(FairVolume* vol) ++volume; /// there are 44 volumes, 36 for the VD (1 for each sensing element) and 8 for the MLOT (1 for each layer) } - if (notSens) { - return kFALSE; // RS: can this happen? This method must be called for sensors only? - } - if (volume < mNumberOfVolumesVD) { subDetID = 0; // VD. For the moment each "chip" is a volume./// TODO: change this logic once the naming scheme is changed } else { @@ -488,10 +634,21 @@ bool Detector::ProcessHits(FairVolume* vol) layer = volume - mNumberOfVolumesVD; } + if (strstr(vol->GetName(), "FT3Sensor_Active") || strstr(vol->GetName(), "FT3Chip")) { + subDetID = 2; + notSens = false; + } + + // TODO: add corresponding logic for disks. I think Ruben is right; this is only called for active volumes! + if (notSens) { + LOG(info) << "ProcessHit called for insensitive volume " << vol->GetName(); + return kFALSE; // RS: can this happen? This method must be called for sensors only? + } + // Is it needed to keep a track reference when the outer ITS volume is encountered? auto stack = (o2::data::Stack*)fMC->GetStack(); // if (fMC->IsTrackExiting() && (lay == 0 || lay == mLayers.size() - 1)) { - if (fMC->IsTrackExiting() && InsideFirstOrLastLayer(vol->GetName())) { + if (fMC->IsTrackExiting() && subDetID < 2 && InsideFirstOrLastLayer(vol->GetName())) { // Keep the track refs for the innermost and outermost layers only o2::TrackReference tr(*fMC, GetDetId()); tr.setTrackID(stack->GetCurrentTrackNumber()); @@ -564,7 +721,9 @@ bool Detector::ProcessHits(FairVolume* vol) } } } /// if VD, for the moment the volume is the "chipID" so no need to retrieve other elments - + else if (subDetID == 2) { + mGeometryTGeo->extractChipIdsFT3(vol->GetName(), layer, stave, chip); + } unsigned short chipID = mGeometryTGeo->getChipIndex(subDetID, volume, layer, stave, halfstave, mod, chip); // Print(vol, volume, subDetID, layer, stave, halfstave, mod, chip, chipID); diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/src/Digitizer.cxx b/Detectors/Upgrades/ALICE3/TRK/simulation/src/Digitizer.cxx index 890c272fefbc2..17b269e950df3 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/src/Digitizer.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/Digitizer.cxx @@ -107,7 +107,7 @@ const o2::trk::ChipSimResponse* Digitizer::getChipResponse(int chipID) return mChipSimRespVD; } - else if (mGeometry->getSubDetID(chipID) == 1) { /// ML/OT + else if (mGeometry->getSubDetID(chipID) == 1 || mGeometry->getSubDetID(chipID) == 2) { /// ML/OT return mChipSimRespMLOT; } return nullptr; @@ -121,12 +121,12 @@ void Digitizer::process(const std::vector* hits, int evID, int srcID, int l LOG(info) << " Digitizing " << mGeometry->getName() << " (ID: " << mGeometry->getDetID() << ") hits of event " << evID << " from source " << srcID << " at time " << mEventTime.getTimeNS() << " ROFrame = " << mNewROFrame - << " Min/Max ROFrames " << mROFrameMin << "/" << mROFrameMax; + << " Min/Max ROFrames " << mROFrameMin << "/" << mROFrameMax << " layer " << layer; - std::cout << "Printing segmentation info: " << std::endl; - SegmentationChip::Print(); + // std::cout << "Printing segmentation info: " << std::endl; + // SegmentationChip::Print(); - // // is there something to flush ? + // is there something to flush ? if (mNewROFrame > mROFrameMin) { fillOutputContainer(mNewROFrame - 1, layer); // flush out all frames preceding the new one } @@ -257,11 +257,11 @@ void Digitizer::processHit(const o2::trk::Hit& hit, uint32_t& maxFr, int evID, i int chipID = hit.GetDetectorID(); //// the chip ID at the moment is not referred to the chip but to a wider detector element (e.g. quarter of layer or disk in VD, stave in ML, half stave in OT) int subDetID = mGeometry->getSubDetID(chipID); - int layer = mGeometry->getLayer(chipID); + int layer = mGeometry->getLayer(chipID); // local layer nr for response int disk = mGeometry->getDisk(chipID); if (disk != -1) { - LOG(debug) << "Skipping disk " << disk; + LOG(debug) << "Skipping VD disk " << disk; return; // skipping hits on disks for the moment } @@ -463,7 +463,7 @@ void Digitizer::processHit(const o2::trk::Hit& hit, uint32_t& maxFr, int evID, i } } } - + LOG(info) << "Response done; adding labels; making digits"; // fire the pixels assuming Poisson(n_response_electrons) o2::MCCompLabel lbl(hit.GetTrackID(), evID, srcID, false); auto roFrameAbs = mNewROFrame + roFrameRel; diff --git a/Detectors/Upgrades/ALICE3/FT3/simulation/src/FT3Layer.cxx b/Detectors/Upgrades/ALICE3/TRK/simulation/src/FT3Layer.cxx similarity index 84% rename from Detectors/Upgrades/ALICE3/FT3/simulation/src/FT3Layer.cxx rename to Detectors/Upgrades/ALICE3/TRK/simulation/src/FT3Layer.cxx index a4424f8ac1b7f..f14393dd866d8 100644 --- a/Detectors/Upgrades/ALICE3/FT3/simulation/src/FT3Layer.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/FT3Layer.cxx @@ -14,10 +14,10 @@ /// \author Mario Sitta /// \author Chinorat Kobdaj (kobdaj@g.sut.ac.th) -#include "FT3Simulation/FT3Layer.h" -#include "FT3Base/GeometryTGeo.h" -#include "FT3Base/FT3BaseParam.h" -#include "FT3Simulation/FT3ModuleConstants.h" +#include "TRKSimulation/FT3Layer.h" +#include "TRKBase/GeometryTGeo.h" +#include "TRKBase/TRKBaseParam.h" +#include "TRKSimulation/FT3ModuleConstants.h" #include // for TGeoManager, gGeoManager #include // for TGeoCombiTrans, TGeoRotation, etc @@ -31,8 +31,7 @@ class TGeoMedium; using namespace TMath; -using namespace o2::ft3; -using namespace o2::itsmft; +using namespace o2::trk; ClassImp(FT3Layer); @@ -235,9 +234,9 @@ void FT3Layer::createReferenceCircles(TGeoVolume* motherVolume, const std::strin TGeoTube* outerCircle = new TGeoTube(mOuterRadius - 0.1, mOuterRadius + 0.1, 0.01); TGeoTube* outerCircleEdge = new TGeoTube(mOuterRadius + 3.3, mOuterRadius + 3.5, 0.01); - TGeoVolume* innerCircleVol = new TGeoVolume((mLayerName + "_InnerCircle").c_str(), innerCircle, gGeoManager->GetMedium("FT3_AIR$")); - TGeoVolume* outerCircleVol = new TGeoVolume((mLayerName + "_OuterCircle").c_str(), outerCircle, gGeoManager->GetMedium("FT3_AIR$")); - TGeoVolume* outerCircleEdgeVol = new TGeoVolume((mLayerName + "_OuterCircleEdge").c_str(), outerCircleEdge, gGeoManager->GetMedium("FT3_AIR$")); + TGeoVolume* innerCircleVol = new TGeoVolume((mLayerName + "_InnerCircle").c_str(), innerCircle, gGeoManager->GetMedium("TRK_AIR$")); + TGeoVolume* outerCircleVol = new TGeoVolume((mLayerName + "_OuterCircle").c_str(), outerCircle, gGeoManager->GetMedium("TRK_AIR$")); + TGeoVolume* outerCircleEdgeVol = new TGeoVolume((mLayerName + "_OuterCircleEdge").c_str(), outerCircleEdge, gGeoManager->GetMedium("TRK_AIR$")); innerCircleVol->SetLineColor(kRed); outerCircleVol->SetLineColor(kBlue); @@ -252,36 +251,36 @@ void FT3Layer::createReferenceCircles(TGeoVolume* motherVolume, const std::strin void FT3Layer::createLayer(TGeoVolume* motherVolume) { - auto& ft3Params = FT3BaseParam::Instance(); + auto& trkParams = TRKBaseParam::Instance(); if (mLayerNumber < 0) { LOG(fatal) << "Invalid layer number " << mLayerNumber << " for FT3 layer."; } - LOG(info) << "FT3: ft3Params.layoutFT3 = " << ft3Params.layoutFT3 + LOG(info) << "FT3: TRKParams.layoutFT3 = " << trkParams.layoutFT3 << " Creating Layer " << mLayerNumber << " at z=" << mZ << " with direction " << mDirection; // ### options for ML and OT disk layout - if (ft3Params.layoutFT3 == kTrapezoidal /*|| (mIsMiddleLayer && ft3Params.layoutFT3 == kSegmented)*/) { + if (trkParams.layoutFT3 == kTrapezoidal /*|| (mIsMiddleLayer && ft3Params.layoutFT3 == kSegmented)*/) { // trapezoidal ML+OT disks // (disks with TGeoTubes doesn'n work properly in ACTS, due to polar coordinates on TGeoTube sides) // (!) Currently (March 12, 2026), only OT disks are segmented --> use Trapezoidal option for ML disks as a simplified segmentation // To be changed to "true" paving with modules, as for the OT disks - std::string chipName = o2::ft3::GeometryTGeo::getFT3ChipPattern() + std::to_string(mLayerNumber); + std::string chipName = GeometryTGeo::getFT3ChipPattern() + std::to_string(mLayerNumber); std::string sensName = Form("%s_%d_%d", GeometryTGeo::getFT3SensorPattern(), mDirection, mLayerNumber); - std::string passiveName = o2::ft3::GeometryTGeo::getFT3PassivePattern() + std::to_string(mLayerNumber); + std::string passiveName = GeometryTGeo::getFT3PassivePattern() + std::to_string(mLayerNumber); - TGeoMedium* medSi = gGeoManager->GetMedium("FT3_SILICON$"); - TGeoMedium* medAir = gGeoManager->GetMedium("FT3_AIR$"); + TGeoMedium* medSi = gGeoManager->GetMedium("TRK_SILICON$"); + TGeoMedium* medAir = gGeoManager->GetMedium("TRK_AIR$"); TGeoTube* layer = new TGeoTube(mInnerRadius, mOuterRadius, mChipThickness / 2); TGeoVolume* layerVol = new TGeoVolume(mLayerName.c_str(), layer, medAir); layerVol->SetLineColor(kGray); - const int NtrapezoidalSegments = ft3Params.nTrapezoidalSegments; + const int NtrapezoidalSegments = trkParams.nTrapezoidalSegments; const double dz = mChipThickness / 2; const double dzSensor = mSensorThickness / 2; @@ -376,47 +375,16 @@ void FT3Layer::createLayer(TGeoVolume* motherVolume) auto* diskRotation = new TGeoRotation("TrapezoidalDiskRotation", 0, 0, 0); auto* diskCombiTrans = new TGeoCombiTrans(0, 0, mZ, diskRotation); motherVolume->AddNode(layerVol, 1, diskCombiTrans); - } else if (ft3Params.layoutFT3 == kCylindrical) { - // cylindrical ML+OT disks - - std::string chipName = o2::ft3::GeometryTGeo::getFT3ChipPattern() + std::to_string(mLayerNumber), - sensName = Form("%s_%d_%d", GeometryTGeo::getFT3SensorPattern(), mDirection, mLayerNumber); - TGeoTube* sensor = new TGeoTube(mInnerRadius, mOuterRadius, mChipThickness / 2); - TGeoTube* chip = new TGeoTube(mInnerRadius, mOuterRadius, mChipThickness / 2); - TGeoTube* layer = new TGeoTube(mInnerRadius, mOuterRadius, mChipThickness / 2); - - TGeoMedium* medSi = gGeoManager->GetMedium("FT3_SILICON$"); - TGeoMedium* medAir = gGeoManager->GetMedium("FT3_AIR$"); - - TGeoVolume* sensVol = new TGeoVolume(sensName.c_str(), sensor, medSi); - sensVol->SetLineColor(kYellow); - TGeoVolume* chipVol = new TGeoVolume(chipName.c_str(), chip, medSi); - chipVol->SetLineColor(kYellow); - TGeoVolume* layerVol = new TGeoVolume(mLayerName.c_str(), layer, medAir); - layerVol->SetLineColor(kYellow); - - LOG(info) << "Inserting " << sensVol->GetName() << " inside " << chipVol->GetName(); - chipVol->AddNode(sensVol, 1, nullptr); - - LOG(info) << "Inserting " << chipVol->GetName() << " inside " << layerVol->GetName(); - layerVol->AddNode(chipVol, 1, nullptr); - - // Finally put everything in the mother volume - auto* FwdDiskRotation = new TGeoRotation("FwdDiskRotation", 0, 0, 180); - auto* FwdDiskCombiTrans = new TGeoCombiTrans(0, 0, mZ, FwdDiskRotation); - - LOG(info) << "Inserting " << layerVol->GetName() << " inside " << motherVolume->GetName(); - motherVolume->AddNode(layerVol, 1, FwdDiskCombiTrans); - } else if (ft3Params.layoutFT3 == kSegmented || - (ft3Params.layoutFT3 == kSegmentedStaveOTOnly && mIsMiddleLayer)) { + } else if (trkParams.layoutFT3 == kSegmentedFT3 || + (trkParams.layoutFT3 == kSegmentedStaveOTOnly && mIsMiddleLayer)) { FT3Module module; // layer structure - std::string frontLayerName = o2::ft3::GeometryTGeo::getFT3LayerPattern() + std::to_string(mDirection) + std::to_string(mLayerNumber) + "_Front"; - std::string backLayerName = o2::ft3::GeometryTGeo::getFT3LayerPattern() + std::to_string(mDirection) + std::to_string(mLayerNumber) + "_Back"; + std::string frontLayerName = GeometryTGeo::getFT3LayerPattern() + std::to_string(mDirection) + std::to_string(mLayerNumber) + "_Front"; + std::string backLayerName = GeometryTGeo::getFT3LayerPattern() + std::to_string(mDirection) + std::to_string(mLayerNumber) + "_Back"; std::string separationLayerName = "FT3SeparationLayer" + std::to_string(mDirection) + std::to_string(mLayerNumber); - TGeoMedium* medAir = gGeoManager->GetMedium("FT3_AIR$"); + TGeoMedium* medAir = gGeoManager->GetMedium("TRK_AIR$"); TGeoVolume* layerVol = nullptr; // Add a little additional room in radius TGeoTube* layer = new TGeoTube(mInnerRadius - 0.1, mOuterRadius + 0.1, 1.5); @@ -434,16 +402,16 @@ void FT3Layer::createLayer(TGeoVolume* motherVolume) LOG(info) << "Inserting " << layerVol->GetName() << " (Rmin=" << mInnerRadius << ", Rmax=" << mOuterRadius << ", z=" << mZ << "cm) inside " << motherVolume->GetName(); motherVolume->AddNode(layerVol, 1, FwdDiskCombiTrans); - } else if (ft3Params.layoutFT3 == kSegmentedStave || - ft3Params.layoutFT3 == kSegmentedStaveOTOnly) { + } else if (trkParams.layoutFT3 == kSegmentedStave || + trkParams.layoutFT3 == kSegmentedStaveOTOnly) { FT3Module module; // layer structure - std::string frontLayerName = o2::ft3::GeometryTGeo::getFT3LayerPattern() + std::to_string(mDirection) + std::to_string(mLayerNumber) + "_Front"; - std::string backLayerName = o2::ft3::GeometryTGeo::getFT3LayerPattern() + std::to_string(mDirection) + std::to_string(mLayerNumber) + "_Back"; + std::string frontLayerName = GeometryTGeo::getFT3LayerPattern() + std::to_string(mDirection) + std::to_string(mLayerNumber) + "_Front"; + std::string backLayerName = GeometryTGeo::getFT3LayerPattern() + std::to_string(mDirection) + std::to_string(mLayerNumber) + "_Back"; std::string separationLayerName = "FT3SeparationLayer" + std::to_string(mDirection) + std::to_string(mLayerNumber); - TGeoMedium* medAir = gGeoManager->GetMedium("FT3_AIR$"); + TGeoMedium* medAir = gGeoManager->GetMedium("TRK_AIR$"); TGeoVolume* layerVol = nullptr; // set up stave config, differs between ML and OT disks @@ -453,12 +421,12 @@ void FT3Layer::createLayer(TGeoVolume* motherVolume) // stave face is at z=0 (or +-z_offset_stave), meaning that volumes are at // ~-+1cm < z < ~+-6cm, the +- referring forward/backward discs double z_layer_thickness = // need to shift internally with this - o2::ft3::ModuleConstants::staveTriangleHeight + - o2::ft3::ModuleConstants::z_offsetStave(staveConfig.x_midpoint_spacing) + - o2::ft3::ModuleConstants::siliconThickness + - o2::ft3::ModuleConstants::copperThickness + - o2::ft3::ModuleConstants::kaptonThickness + - o2::ft3::ModuleConstants::epoxyThickness * 2 + + o2::trk::FT3ModuleConstants::staveTriangleHeight + + o2::trk::FT3ModuleConstants::z_offsetStave(staveConfig.x_midpoint_spacing) + + o2::trk::FT3ModuleConstants::siliconThickness + + o2::trk::FT3ModuleConstants::copperThickness + + o2::trk::FT3ModuleConstants::kaptonThickness + + o2::trk::FT3ModuleConstants::epoxyThickness * 2 + 0.5; // add some extra room to ensure all volumes are encapsulated // shift stave volumes into layer volume, since nominal z_{stave face} = 0 @@ -468,7 +436,7 @@ void FT3Layer::createLayer(TGeoVolume* motherVolume) TGeoTube* layer = new TGeoTube(mInnerRadius - 0.2, mOuterRadius + 3.49, z_layer_thickness / 2); layerVol = new TGeoVolume(mLayerName.c_str(), layer, medAir); - if (ft3Params.drawReferenceCircles) { + if (trkParams.drawReferenceCircles) { std::string referenceCirclesName = "ReferenceCircles_Dir" + std::to_string(mDirection) + "_Layer" + std::to_string(mLayerNumber); createReferenceCircles(layerVol, referenceCirclesName); // for visualization purposes } @@ -486,6 +454,6 @@ void FT3Layer::createLayer(TGeoVolume* motherVolume) motherVolume->AddNode(layerVol, 1, FwdDiskCombiTrans); } else { - LOG(fatal) << "Unknown FT3 layout option: " << static_cast(ft3Params.layoutFT3); + LOG(fatal) << "Unknown FT3 layout option: " << static_cast(trkParams.layoutFT3); } } diff --git a/Detectors/Upgrades/ALICE3/FT3/simulation/src/FT3Module.cxx b/Detectors/Upgrades/ALICE3/TRK/simulation/src/FT3Module.cxx similarity index 99% rename from Detectors/Upgrades/ALICE3/FT3/simulation/src/FT3Module.cxx rename to Detectors/Upgrades/ALICE3/TRK/simulation/src/FT3Module.cxx index 4c9041b17fcec..4e89d5c0f7c72 100644 --- a/Detectors/Upgrades/ALICE3/FT3/simulation/src/FT3Module.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/FT3Module.cxx @@ -12,8 +12,8 @@ /// \file FT3Module.cxx /// \brief Implementation of the FT3Module class -#include "FT3Simulation/FT3Module.h" -#include "FT3Base/FT3BaseParam.h" +#include "TRKSimulation/FT3Module.h" +#include "TRKBase/TRKBaseParam.h" #include #include #include @@ -132,8 +132,8 @@ std::pair calculate_y_range( } /* - * This function is a helper function which will pad out the stave with sensors - * until there is no more space available. + * This function is a helper function to determine the positions of senors on the stave + * by padding out the stave with sensors until there is no more space available. * * Arguments: * y_positions: a pair of vectors, where each vector contains pairs of @@ -500,7 +500,7 @@ void FT3Module::create_layout_staveGeo(double mZ, int layerNumber, int direction << direction << ", Layer " << layerNumber; FT3Module::initialize_materials(); - auto& ft3Params = o2::ft3::FT3BaseParam::Instance(); + auto& trkParams = o2::trk::TRKBaseParam::Instance(); // First let's define some constants used throughout /* @@ -562,7 +562,7 @@ void FT3Module::create_layout_staveGeo(double mZ, int layerNumber, int direction // default positive and negative starting points has a gap around x-axis for symmetry double stave_half_length = staveConfig.y_lengths[i_stave] / 2; PositionRangeType y_ranges; - if (ft3Params.placeSensorStackInMiddleOfStave) { + if (trkParams.placeSensorStackInMiddleOfStave) { /* * We want a sensor stack to cross over the x-axis for coverage at y=0 * N.B. not necessarily exactly mirrored, only if stack gap is the same @@ -597,11 +597,11 @@ void FT3Module::create_layout_staveGeo(double mZ, int layerNumber, int direction // Define tolerances for cutting staves and placing sensors double tolerance_inner, tolerance_outer; if (staveConfig.isML) { - tolerance_inner = ft3Params.staveTolMLInner; - tolerance_outer = ft3Params.staveTolMLOuter; + tolerance_inner = trkParams.staveTolFT3MLInner; + tolerance_outer = trkParams.staveTolFT3MLOuter; } else { - tolerance_inner = ft3Params.staveTolOTInner; - tolerance_outer = ft3Params.staveTolOTOuter; + tolerance_inner = trkParams.staveTolFT3OTInner; + tolerance_outer = trkParams.staveTolFT3OTOuter; } // cut staves on nominal inner radius if specified if (tolerance_inner > staveConfig.maxToleranceInner) { @@ -735,7 +735,7 @@ void FT3Module::create_layout_staveGeo(double mZ, int layerNumber, int direction x_mid - Constants::active_width / 2, y_mid, z_mid, true); // right single sensor of the 2x1 addSingleSensorVolume( - motherVolume, layerNumber, direction, i_stave, sensor_count, + motherVolume, layerNumber, direction, i_stave, sensor_count + 1, x_mid + Constants::active_width / 2, y_mid, z_mid, false); // ------------ (2) Epoxy glue layer between silicon and copper (FPC) ------------ z_mid = z_offset_to_glue_Si * z_offset_multiplier + z_stave_shift; @@ -759,7 +759,7 @@ void FT3Module::create_layout_staveGeo(double mZ, int layerNumber, int direction x_mid, y_mid, z_mid, "CarbonKapton"); // increment to next sensor: (height + gap of one sensor) y_mid += y_sign * (Constants::sensor2x1_height + Constants::sensor2x1_gap); - sensor_count++; // same count for each material in the glued stack of materials + sensor_count += 2; // same count for each material in the glued stack of materials } // sensors in stack } // for y_sign (writing of positive or negative y positions) } // i_y_pos diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKServices.cxx b/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKServices.cxx index e3855dbde6535..58813c353aa97 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKServices.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKServices.cxx @@ -21,8 +21,6 @@ #include #include -#include - #include #include diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKSimulationLinkDef.h b/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKSimulationLinkDef.h index 282fc72becc52..7a1d5d6d00f94 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKSimulationLinkDef.h +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKSimulationLinkDef.h @@ -18,6 +18,8 @@ #pragma link C++ class o2::trk::Hit + ; #pragma link C++ class std::vector < o2::trk::Hit> + ; +#pragma link C++ class o2::trk::FT3Layer + ; + #pragma link C++ class o2::trk::TRKCylindricalLayer + ; #pragma link C++ class o2::trk::TRKSegmentedLayer + ; #pragma link C++ class o2::trk::TRKMLLayer + ; @@ -30,8 +32,6 @@ #pragma link C++ class o2::trk::ChipSimResponse + ; #pragma link C++ class o2::trk::DPLDigitizerParam < o2::detectors::DetID::TRK> + ; -#pragma link C++ class o2::trk::DPLDigitizerParam < o2::detectors::DetID::FT3> + ; #pragma link C++ class o2::conf::ConfigurableParamHelper < o2::trk::DPLDigitizerParam < o2::detectors::DetID::TRK>> + ; -#pragma link C++ class o2::conf::ConfigurableParamHelper < o2::trk::DPLDigitizerParam < o2::detectors::DetID::FT3>> + ; #endif diff --git a/Detectors/Upgrades/README.md b/Detectors/Upgrades/README.md index febcb18e746be..c32b1e4a44037 100644 --- a/Detectors/Upgrades/README.md +++ b/Detectors/Upgrades/README.md @@ -18,7 +18,6 @@ Currently two sections are included: diff --git a/Steer/DigitizerWorkflow/src/TRKDigitizerSpec.cxx b/Steer/DigitizerWorkflow/src/TRKDigitizerSpec.cxx index 06d922cc1a117..32018921c7af7 100644 --- a/Steer/DigitizerWorkflow/src/TRKDigitizerSpec.cxx +++ b/Steer/DigitizerWorkflow/src/TRKDigitizerSpec.cxx @@ -279,7 +279,7 @@ class TRKDPLDigitizerTask : BaseDPLDigitizer const auto& dopt = o2::trk::DPLDigitizerParam::Instance(); // pc.inputs().get("TRK_almiraparam"); const auto& aopt = o2::trk::AlmiraParam::Instance(); - mLayers = constants::VD::petal::nLayers + geom->getNumberOfLayersMLOT(); + mLayers = constants::VD::petal::nLayers + geom->getNumberOfLayersMLOT() + geom->getNumberOfDisksMLOT(); mDigits.resize(mLayers); mROFRecords.resize(mLayers); mROFRecordsAccum.resize(mLayers); diff --git a/macro/CMakeLists.txt b/macro/CMakeLists.txt index 0bb5650364b06..d6ffa9d4e8399 100644 --- a/macro/CMakeLists.txt +++ b/macro/CMakeLists.txt @@ -114,7 +114,6 @@ if(ENABLE_UPGRADES) set(upgradeTargets O2::Alice3DetectorsPassive O2::ITS3Simulation - O2::FT3Simulation O2::FCTSimulation O2::IOTOFSimulation O2::RICHSimulation diff --git a/macro/build_geometry.C b/macro/build_geometry.C index e46b45254d308..b4924ebd35d5d 100644 --- a/macro/build_geometry.C +++ b/macro/build_geometry.C @@ -51,7 +51,6 @@ #endif #ifdef ENABLE_UPGRADES -#include #include #include #include @@ -254,11 +253,6 @@ void build_geometry(FairRunSim* run = nullptr) "O2TRKSimulation", "create_detector_trk", isReadout("TRK"))); } - if (isActivated("FT3")) { - // ALICE 3 FT3 - addReadoutDetector(new o2::ft3::Detector(isReadout("FT3"))); - } - if (isActivated("FCT")) { // ALICE 3 FCT addReadoutDetector(new o2::fct::Detector(isReadout("FCT"))); diff --git a/run/CMakeLists.txt b/run/CMakeLists.txt index 474aa7e41eb7c..7dae47b4a742a 100644 --- a/run/CMakeLists.txt +++ b/run/CMakeLists.txt @@ -41,7 +41,6 @@ target_link_libraries(allsim $<$:O2::Alice3DetectorsPassive> $<$:O2::ITS3Simulation> $<$:O2::TRKSimulation> - $<$:O2::FT3Simulation> $<$:O2::FCTSimulation> $<$:O2::IOTOFSimulation> $<$:O2::RICHSimulation> diff --git a/run/O2HitMerger.h b/run/O2HitMerger.h index 2f54a8b5d202a..20280294fbb81 100644 --- a/run/O2HitMerger.h +++ b/run/O2HitMerger.h @@ -73,7 +73,6 @@ #ifdef ENABLE_UPGRADES #include -#include #include #include #include @@ -1019,10 +1018,6 @@ void O2HitMerger::initDetInstances() mDetectorInstances[i] = std::move(std::make_unique(true)); counter++; } - if (i == DetID::FT3) { - mDetectorInstances[i] = std::move(std::make_unique(true)); - counter++; - } if (i == DetID::FCT) { mDetectorInstances[i] = std::move(std::make_unique(true)); counter++;