diff --git a/core/data/trd/CbmTrdCluster.cxx b/core/data/trd/CbmTrdCluster.cxx index 0c49524486df0e9e5158395b273e56cca963bf1c..eca15855aa491ce6782950eb981a2a77f2dbce1e 100644 --- a/core/data/trd/CbmTrdCluster.cxx +++ b/core/data/trd/CbmTrdCluster.cxx @@ -140,7 +140,12 @@ Int_t CbmTrdCluster::IsChannelInRange(Int_t ch) const Bool_t CbmTrdCluster::Merge(CbmTrdCluster* second) { if (GetRow() != second->GetRow()) return kFALSE; - if (TMath::Abs(second->fStartTime - fStartTime) > 20) return kFALSE; + // time difference condition + if (fNCols == 1 || second->fNCols == 1) { + if (TMath::Abs(second->fStartTime - fStartTime) > 50) return kFALSE; + } + else if (TMath::Abs(second->fStartTime - fStartTime) > 20) + return kFALSE; // look before current if (second->fStartCh + second->fNCols == fStartCh && !second->HasOpenStop() && !HasOpenStart()) { // cout<<"Merge before with "<<second->ToString(); diff --git a/core/data/trd/CbmTrdHit.cxx b/core/data/trd/CbmTrdHit.cxx index 1a23ab122168ec4d646db89ff5d75ac6888bc81b..0006a58fd3f4fe5be425d3aafaa0f39d1f4ebecf 100644 --- a/core/data/trd/CbmTrdHit.cxx +++ b/core/data/trd/CbmTrdHit.cxx @@ -18,7 +18,7 @@ using std::endl; using std::stringstream; -CbmTrdHit::CbmTrdHit() : CbmPixelHit(), fDefine(0), fELoss(-1.) +CbmTrdHit::CbmTrdHit() : CbmPixelHit(), fDefine(0), fNeighborId(-1), fELoss(-1.) { SetType(kTRDHIT); SetTime(-1); @@ -29,6 +29,7 @@ CbmTrdHit::CbmTrdHit(Int_t address, const TVector3& pos, const TVector3& dpos, D Double_t eLoss, Double_t time, Double_t timeError) : CbmPixelHit(address, pos, dpos, dxy, refId) , fDefine(0) + , fNeighborId(-1) , fELoss(eLoss) { SetType(kTRDHIT); diff --git a/core/data/trd/CbmTrdHit.h b/core/data/trd/CbmTrdHit.h index 5b24930c02bc6c8e1538885eb90779dcf1423b56..a8b3d5e7904bff5c214c3b0a0334253b34c758f0 100644 --- a/core/data/trd/CbmTrdHit.h +++ b/core/data/trd/CbmTrdHit.h @@ -80,6 +80,7 @@ public: Bool_t GetMaxType() const { return TESTBIT(fDefine, kMaxType); } Bool_t HasOverFlow() const { return TESTBIT(fDefine, kOvfl); } Bool_t IsRowCross() const { return TESTBIT(fDefine, kRowCross); } + Bool_t IsUsed() const { return (GetRefId() < 0); } /** Setters **/ void SetELoss(Double_t loss) { fELoss = loss; } @@ -94,9 +95,10 @@ public: private: UChar_t fDefine; // hit extra info + Int_t fNeighborId; // refId in case of row cross clusters Double32_t fELoss; // Energy deposit due to TR + dEdx - ClassDef(CbmTrdHit, 3); + ClassDef(CbmTrdHit, 4); }; #endif diff --git a/core/detectors/trd/CbmTrdParModGas.cxx b/core/detectors/trd/CbmTrdParModGas.cxx index e65fa1c3eeed740deb0483aa9bb0a4858ccccc67..61e97f6f2a515999a5d887d09d502752f076b976 100644 --- a/core/detectors/trd/CbmTrdParModGas.cxx +++ b/core/detectors/trd/CbmTrdParModGas.cxx @@ -118,6 +118,33 @@ Float_t CbmTrdParModGas::EkevFC(Float_t ekev) const // return (sFASP-s0FASP)/gFASP; } +//_______________________________________________________________________________________________ +Float_t CbmTrdParModGas::EfCkeV(Float_t efC) const +{ + /** Convert energy deposit to no of primary ionisations and apply gas gain. + * Currently gas gain is evaluated from 55Fe spectrum analysis on ArCO2(80/20) + */ + + Int_t gasId = GetNobleGasType() - 1; + Float_t wi = (1. - fPercentCO2) * fgkWi[gasId] + fPercentCO2 * fgkWi[2]; + + //gas gain + // G = G[ev->ADC] * wi[ArCO2]/C[mV->ADC]/A[fC->mV]/e + // G[ev->ADC] : measured gain based on 55Fe spectrum (expo) + // wi[ArCO2] : average energy to produce a ele-ion pair in mixture (27.24 ev) + // C[mV->ADC] : FASP out [2V] to ADC range [4096 ch] (2) + // A[fC->mV] : FASP gain from CADENCE (6) + // e : 1.6e-4 [fC] electric charge + Double_t gain = 170.25 * TMath::Exp(fgkGGainUaPar[0] + fgkGGainUaPar[1] * fUa * 1.e-3) + / 12.; // for Xe correct Ar gain measurements TODO + if (gasId == 0) gain *= 0.6; + + Float_t ekev = efC * wi / gain / 0.16; + if (VERBOSE) + printf(" ua[V]=%d gain[%5.2e] wi[eV]=%5.2f :: E[keV]=%6.3f E[fC]=%6.2f\n", fUa, gain, wi, ekev, efC); + return ekev; +} + //_______________________________________________________________________________________________ Int_t CbmTrdParModGas::GetShellId(const Char_t shell) const { diff --git a/core/detectors/trd/CbmTrdParModGas.h b/core/detectors/trd/CbmTrdParModGas.h index 3a2c7efaddfc5abe0947299c89d9ee41c9955f53..b98d0d344d1f3936bfab7022ceff2e9701b40a97 100644 --- a/core/detectors/trd/CbmTrdParModGas.h +++ b/core/detectors/trd/CbmTrdParModGas.h @@ -49,6 +49,11 @@ public: * \return charge at FASP input in fC */ Float_t EkevFC(Float_t ekev) const; + /** \brief Convert pad-plane charge in fC to energy deposit [keV] taking into account the gas gain + * \param[in] efc charge in fC + * \return energy deposit in keV + */ + Float_t EfCkeV(Float_t efc) const; TString GetFileName() const { return fFileNamePID; } Double_t GetNobleGas() const { return 1. - fPercentCO2; } const Char_t* GetNobleGasName() const { return (GetNobleGasType() - 1 ? "Ar" : "Xe"); } diff --git a/macro/trd/geometry/trd.v18/Create_TRD_Geometry_v18b.C b/macro/trd/geometry/trd.v18/Create_TRD_Geometry_v18b.C new file mode 100644 index 0000000000000000000000000000000000000000..057a85394296fd74c6359795e59e723f43f2cf5b --- /dev/null +++ b/macro/trd/geometry/trd.v18/Create_TRD_Geometry_v18b.C @@ -0,0 +1,4365 @@ +/* Copyright (C) 2019 Horia Hulubei National Institute of Physics and Nuclear Engineering, Bucharest + SPDX-License-Identifier: GPL-3.0-only + Authors: Alexandru Bercuci [committer] */ + +/// +/// \file Create_TRD_Geometry_v18b.C +/// \brief Generates TRD geometry in Root format. +/// + +// 2019-04-15 - AB - v18b - put TRD layers at z-positions according to proposed CAD frame design (v20a for the TDR version). +// 2019-04-15 - AB - v18a - using TRD Bucharest chambers with FASP for the inner zone. +// 2017-06-02 - DE - v17n - increase pad granularity wrt v17l: type 6 = 24 rows, type 8 = 8 rows +// 2017-05-31 - DE - v17l - increase large module size to 96/99 cm +// 2017-05-25 - DE - v17k - use only 4 module types: 1, 3, 6, 8 +// 2017-05-25 - DE - v17j - re-arrange inner zone to allow for a 2x1 hole +// 2017-04-28 - DE - v17 - implement power bus bars as defined in the TDR +// 2017-04-26 - DE - v17 - add aluminium ledge around backpanel +// 2017-04-25 - DE - v17c_3e - reduce the number of FEBs on the small modules from 10, 6, 4 to 8, 4 and 2 +// 2017-02-14 - DE - v17b_3e - build TRD from ROB-3 only, optimise layout +// 2017-01-10 - DE - v17a_3e - replace 6 ultimate density by 9 super density FEBs for TRD type 1 modules +// 2016-07-05 - FU - v16a_3e - identical to v15a, change the way the trd volume is exported to resolve a bug with TGeoShape destructor +// 2015-01-08 - DE - v15a_3e - reduce frame thickness in large modules to 15 mm instead of 20 mm +// 2014-06-25 - DE - v14a_3e - consists of only 3 small and 3 large modules types (was 4+4 before) +// 2014-06-25 - DE - v14a_3e - inner part of all 3 stations is now identical +// 2014-05-02 - DE - v14a_3e - redesign inner part of station 3, now with 5x5-1 small modules, like in station 1 and station 2 +// 2014-05-02 - DE - v14a_3e - include optional GBTX readout boards on each module +// 2014-05-02 - DE - v14a_3e - introduce 3x5=15 Spadic FEBs for ultimate density on module type 1 +// +// 2013-11-14 - DE - v13q_3e - generate information about pad plane layout (CbmTrdPads_v14a.h) for all module types in this macro +// +// 2013-11-04 - DE - v13p4 - adapt the number of front-end boards to the pad layout of the 540 mm modules +// 2013-11-04 - DE - v13p4 - use 8 module types (4x S + 4x L) to better match the occupancy +// 2013-10-31 - DE - v13p4 - modify the support structure of station 1 to match with the MUCH/RICH platform +// 2013-10-29 - DE - v13p4 - build lattice grid as TGeoBBox instead of VolumeAssembly - in run_sim.C save 9% of time compared to v13p7 +// 2013-10-29 - DE - v13p4 - build lattice grid as TGeoBBox instead of CompositeShape - in run_sim.C save 18% of time compared to v13p6 +// +// 2013-10-28 - DE - introduce new geometry naming scheme: v13p1 - SIS 100 hadron +// 2013-10-28 - DE - introduce new geometry naming scheme: v13p2 - SIS 100 electron +// 2013-10-28 - DE - introduce new geometry naming scheme: v13p3 - SIS 100 muon +// 2013-10-28 - DE - introduce new geometry naming scheme: v13p4 - SIS 300 electron +// 2013-10-28 - DE - introduce new geometry naming scheme: v13p5 - SIS 300 muon +// 2013-10-28 - DE - add option to draw the magnetic field vector in the magnet +// 2013-09-27 - DE - do not use TGeoXtru to build the supports, use TGeoBBox instead +// +// 2013-06-25 - DE - v13g trd300_rich (10 layers, z = 4100 ) - TRD right behind SIS300 RICH +// 2013-06-25 - DE - v13h trd100_sts ( 4 layers, z = 2600 ) - TRD completely on RICH/MUCH platform to allow TOF to move upstream +// 2013-06-25 - DE - v13i trd100_rich ( 2 layers, z = 4100 ) - TRD right behind RICH +// 2013-06-25 - DE - v13j trd100_rich ( 3 layers, z = 4100 ) - TRD right behind RICH +// 2013-06-25 - DE - v13k trd100_rich ( 4 layers, z = 4100 ) - TRD right behind RICH +// 2013-06-25 - DE - --- trd100_much_2_absorbers ( 4 layers, z = 4300 ) - same as version at z = 4600 +// 2013-06-25 - DE - v13l trd100_much_3_absorbers ( 4 layers, z = 4600 ) - TRD right behind SIS100 MUCH +// 2013-06-25 - DE - v13m trd300_much_6_absorbers (10 layers, z = 5500 ) - TRD right behind SIS300 MUCH +// 2013-06-25 - DE - v13n trd300_rich_stretched (10 layers, z = 4600 ) - TRD stretched behind SIS300 RICH +// +// 2013-06-19 - DE - add TRD (I, II, III) labels on support structure +// 2013-05-29 - DE - allow for flexible TRD z-positions defined by position of layer01 +// 2013-05-23 - DE - remove "trd_" prefix from node names (except top node) +// 2013-05-22 - DE - radiators G30 (z=240 mm) +// 2013-05-22 - DE - radiators H (z=275 mm - 125 * 2.2mm), (H++ z=335 mm) +// 2013-05-22 - DE - radiators B++ (z=254 mm - 350 * 0.724 mm), K++ (z=254 mm - 350 * 0.724 mm) +// 2013-04-17 - DE - introduce volume assembly for layers, e.g. trd_layer03 +// 2013-03-26 - DE - use Air as ASIC material +// 2013-03-26 - DE - put support structure into its own assembly +// 2013-03-26 - DE - move TRD upstream to z=400m +// 2013-03-26 - DE - RICH will probably end at z=380 cm, TRD can move to 400 cm +// 2013-03-25 - DE - shrink active area from 570 to 540 mm and 960 to 910 mm +// 2013-03-06 - DE - add ASICs on FEBs +// 2013-03-05 - DE - introduce supports for SIS100 and SIS300 +// 2013-03-05 - DE - replace all Float_t by Double_t +// 2013-01-21 - DE - introduce TRD media, use TRDG10 as material for pad plane and FEBs +// 2013-01-21 - DE - put backpanel into the geometry +// 2013-01-11 - DE - allow for misalignment of TRD modules +// 2012-11-04 - DE - add kapton foil, add FR4 padplane +// 2012-11-03 - DE - add lattice grid on entrance window as CompositeShape + +// TODO: +// - use Silicon as ASIC material + +// in root all sizes are given in cm + +#include "TDatime.h" +#include "TFile.h" +#include "TGeoArb8.h" +#include "TGeoCompositeShape.h" +#include "TGeoCone.h" +#include "TGeoManager.h" +#include "TGeoMaterial.h" +#include "TGeoMatrix.h" +#include "TGeoMedium.h" +#include "TGeoPgon.h" +#include "TGeoTube.h" +#include "TGeoVolume.h" +#include "TGeoXtru.h" +#include "TList.h" +#include "TRandom3.h" +#include "TString.h" +#include "TSystem.h" + +#include <iostream> + +// Name of output file with geometry +const TString tagVersion = "v18b"; +//const TString subVersion = "_1h"; +//const TString subVersion = "_1e"; +//const TString subVersion = "_1m"; +//const TString subVersion = "_3e"; +//const TString subVersion = "_3m"; + +const Int_t setupid = 1; // 1e is the default +//const Double_t zfront[5] = { 260., 410., 360., 410., 550. }; // original +const Double_t zfront[5] = {435., // SIS100 hadron + 435., // SIS100 electron + 472., // SIS100 muon + 410., 550.}; // muon_jpsi and muon_lmvm +const TString setupVer[5] = {"_1h", "_1e", "_1m", "_3e", "_3m"}; +const TString subVersion = setupVer[setupid]; + +const TString geoVersion = "trd_" + tagVersion + subVersion; +const TString FileNameSim = geoVersion + ".geo.root"; +const TString FileNameGeo = geoVersion + "_geo.root"; +const TString FileNameInfo = geoVersion + ".geo.info"; +const TString FileNamePads = "CbmTrdPads_" + tagVersion + ".h"; + +// display switches +const Bool_t IncludeRadiator = true; // if radiator is included in geometry +const Bool_t IncludeLattice = true; // if lattice grid is included in geometry +const Bool_t IncludeKaptonFoil = true; // if entrance window is included in geometry +const Bool_t IncludeGasFrame = true; // if frame around gas volume is included in geometry +const Bool_t IncludePadplane = true; // if padplane is included in geometry +const Bool_t IncludeBackpanel = true; // if backpanel is included in geometry +const Bool_t IncludeAluLedge = true; // if Al-ledge around the backpanel is included in geometry +const Bool_t IncludePowerbars = true; // if LV copper bus bars to be drawn +const Bool_t IncludeFebs = true; // if FEBs are included in geometry +const Bool_t IncludeRobs = true; // if ROBs are included in geometry +const Bool_t IncludeAsics = true; // if ASICs are included in geometry +const Bool_t IncludeSupports = true; // if support structure is included in geometry +const Bool_t IncludeLabels = true; // if TRD (I, II, III) labels are plotted in (VisLevel 5) +const Bool_t IncludeFieldVector = false; // if magnetic field vector to be shown (in the magnet) + +// positioning switches +const Bool_t DisplaceRandom = false; // add random displacement of modules for alignment study +const Bool_t RotateRandom = false; // add random rotation of modules for alignment study +const Bool_t DoExplode = false; // add random displacement of modules for alignment study + +// positioning parameters +const Double_t maxdx = 0.2; // max +- 0.1 cm shift in x +const Double_t maxdy = 0.2; // max +- 0.1 cm shift in y +const Double_t maxdz = 1.0; // max +- 1.0 cm shift in z + +const Double_t maxdrotx = 2.0; // 20.0; // max rotation around x +const Double_t maxdroty = 2.0; // 20.0; // max rotation around y +const Double_t maxdrotz = 2.0; // 20.0; // max rotation around z + +const Double_t ExplodeFactor = 1.02; // 1.02; // Factor by which modules are exploded in the x/y plane + +// initialise random numbers +TRandom3 r3(0); + +// Parameters defining the layout of the complete detector build out of different detector layers. +const Int_t MaxLayers = 10; // max layers + +// select layers to display +// +//const Int_t ShowLayer[MaxLayers] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; // 1st layer only +//const Int_t ShowLayer[MaxLayers] = { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 }; // 2nd layer only +//const Int_t ShowLayer[MaxLayers] = { 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }; // 5th layer only +//const Int_t ShowLayer[MaxLayers] = { 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 }; // 6th layer only +//const Int_t ShowLayer[MaxLayers] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 }; // 9th layer only +//const Int_t ShowLayer[MaxLayers] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; // 10th layer only +// +//const Int_t ShowLayer[MaxLayers] = { 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 }; // Station 1, layer 1, 2 +//const Int_t ShowLayer[MaxLayers] = { 0, 0, 0, 0, 1, 1, 0, 0, 0, 0 }; // Station 2, layer 5, 6 +//const Int_t ShowLayer[MaxLayers] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 }; // Station 3, layer 9,10 +//const Int_t ShowLayer[MaxLayers] = { 1, 1, 0, 0, 1, 1, 0, 0, 0, 0 }; // Station 1 and 2 +//const Int_t ShowLayer[MaxLayers] = { 1, 1, 0, 0, 1, 1, 1, 0, 1, 1 }; // Station 1, 2 and 3 +// +//const Int_t ShowLayer[MaxLayers] = { 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 }; // SIS100-2l // 1: plot, 0: hide +//const Int_t ShowLayer[MaxLayers] = { 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 }; // SIS100-3l // 1: plot, 0: hide +// +//const Int_t ShowLayer[MaxLayers] = { 1, 1, 1, 1, 0, 0, 0, 0, 0, 0 }; // SIS100-4l // 1: plot, 0: hide +//const Int_t ShowLayer[MaxLayers] = { 0, 0, 0, 0, 1, 1, 1, 1, 1, 1 }; // SIS300-mu // 1: plot, 0: hide +//const Int_t ShowLayer[MaxLayers] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; // SIS300-e // 1: plot, 0: hide +Int_t ShowLayer[MaxLayers] = {1, 1, 1, 1, 0, 0, 0, 0, 0, 0}; // SIS100-4l is default +//{ 1, 1, 1, 1, 0, 0, 0, 0, 0, 0 }; // SIS100-4l is default + +Int_t BusBarOrientation[MaxLayers] = {1, 1, 1, 1, 0, 0, 0, 0, 0, 0}; // 1 = vertical + +Int_t PlaneId[MaxLayers]; // automatically filled with layer ID + +const Int_t LayerType[MaxLayers] = {10, 11, 10, 11, 20, 21, + 20, 21, 30, 31}; // ab: a [1-3] - layer type, b [0,1] - vertical/horizontal pads +// ### Layer Type 11 is Layer Type 1 with detector modules rotated by 90° +// ### Layer Type 21 is Layer Type 2 with detector modules rotated by 90° +// ### Layer Type 31 is Layer Type 3 with detector modules rotated by 90° + +// In the subroutine creating the layers this is recognized automatically + +const Int_t LayerNrInStation[MaxLayers] = {1, 2, 3, 4, 1, 2, 3, 4, 1, 2}; + +Double_t LayerPosition[MaxLayers] = {0.}; // start position = 0 - 2016-07-12 - DE + +// 5x z-positions from 260 till 550 cm +//Double_t LayerPosition[MaxLayers] = { 260. }; // start position - 2013-10-28 - DE - v14_1h - SIS 100 hadron ( 4 layers, z = 2600 ) +//Double_t LayerPosition[MaxLayers] = { 410. }; // start position - 2013-10-28 - DE - v14_1e - SIS 100 electron ( 4 layers, z = 4100 ) +//Double_t LayerPosition[MaxLayers] = { 360. }; // start position - 2014-06-16 - DE - v14_1m - SIS 100 muon ( 4 layers, z = 3600 ) was 460. +//Double_t LayerPosition[MaxLayers] = { 410. }; // start position - 2013-10-28 - DE - v14_3e - SIS 300 electron (10 layers, z = 4100 ) +//Double_t LayerPosition[MaxLayers] = { 550. }; // start position - 2013-10-28 - DE - v14_3m - SIS 300 muon 6_abs (10 layers, z = 5500 ) +// +// obsolete variants +//Double_t LayerPosition[MaxLayers] = { 460. }; // start position - 2013-10-28 - DE - v13x3 - SIS 100 muon ( 4 layers, z = 4600 ) +//Double_t LayerPosition[MaxLayers] = { 410. }; // start position - 2013-06-25 - DE - v13i trd100_rich ( 2 layers, z = 4100 ) +//Double_t LayerPosition[MaxLayers] = { 410. }; // start position - 2013-06-25 - DE - v13j trd100_rich ( 3 layers, z = 4100 ) +//Double_t LayerPosition[MaxLayers] = { 430. }; // start position - 2013-06-25 - DE - --- trd100_much_2_absorbers ( 4 layers, z = 4300 ) +//Double_t LayerPosition[MaxLayers] = { 460. }; // start position - 2013-06-25 - DE - v13n trd300_rich_stretched (10 layers, z = 4600 ) + + +const Double_t LayerThickness = 71.0; //45.0; // Thickness of one TRD layer in cm +const Double_t LayerOffset[MaxLayers] = {0., 0., 0., 0., 5., + 0., 0., 0., 5., 0.}; // v13x[4,5] - z offset in addition to LayerThickness +//const Double_t LayerOffset[MaxLayers] = { 0., 0., 0., 0., 0., 0., 0., 0., 0., 0. }; // SIS100 - z offset in addition to LayerThickness +//const Double_t LayerOffset[MaxLayers] = { 0., 0., 0., 0., 95., 0., 0., 0., 5., 0. }; // v13n - z offset in addition to LayerThickness + +const Int_t LayerArraySize[3][4] = {{9, 4, 9, 11}, // for layer[1-3][i,o] below + {5, 5, 9, 11}, + {5, 5, 9, 11}}; + + +// ### Layer Type 1 +// v14x - module types in the inner sector of layer type 1 - looking upstream +const Int_t layer1i[9][4] = { // abc: a module type - b orientation (x90 deg) in odd - c even layers + {323, 323, 321, 321}, {323, 323, 321, 321}, {323, 323, 321, 321}, {900, 900, 900, 900}, {900, 0, 0, 900}, + {900, 900, 900, 900}, {303, 303, 301, 301}, {303, 303, 301, 301}, {303, 303, 301, 301}}; // number of modules: 24 + +// v14x - module types in the outer sector of layer type 1 - looking upstream +const Int_t layer1o[9][11] = {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 723, 723, 0, 0, 0, 721, 721, 0, 0}, {0, 0, 723, 523, 0, 0, 0, 521, 721, 0, 0}, + {0, 0, 503, 503, 0, 0, 0, 501, 501, 0, 0}, {0, 0, 703, 503, 0, 0, 0, 501, 701, 0, 0}, + {0, 0, 703, 703, 0, 0, 0, 701, 701, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}; +// number of modules: 26 +// Layer1 = 24 + 26; // v14a + + +// ### Layer Type 2 +// v14x - module types in the inner sector of layer type 2 - looking upstream +const Int_t layer2i[5][5] = { // abc: a module type - b orientation (x90 deg) in odd - c even layers + {323, 323, 321, 321, 321}, + {223, 123, 121, 121, 221}, + {203, 103, 0, 101, 201}, + {203, 103, 101, 101, 201}, + {303, 303, 301, 301, 301}}; // number of modules: 24 + +// v14x - module types in the outer sector of layer type 2 - looking upstream +const Int_t layer2o[9][11] = {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 823, 823, 823, 823, 821, 821, 821, 821, 821, 0}, + {0, 823, 823, 823, 723, 721, 721, 821, 821, 821, 0}, + {0, 823, 723, 623, 0, 0, 0, 621, 721, 821, 0}, + {0, 803, 703, 603, 0, 0, 0, 601, 701, 801, 0}, + {0, 803, 703, 603, 0, 0, 0, 601, 701, 801, 0}, + {0, 803, 803, 803, 703, 701, 701, 801, 801, 801, 0}, + {0, 803, 803, 803, 803, 801, 801, 801, 801, 801, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}; +// number of modules: 54 +// Layer2 = 24 + 54; // v14a + + +// ### Layer Type 3 +// v14x - module types in the inner sector of layer type 3 - looking upstream +const Int_t layer3i[5][5] = { // abc: a module type - b orientation (x90 deg) in odd - c even layers + {323, 323, 321, 321, 321}, + {223, 123, 121, 121, 221}, + {203, 103, 0, 101, 201}, + {203, 103, 101, 101, 201}, + {303, 303, 301, 301, 301}}; +// number of modules: 24 + +// v14x - module types in the outer sector of layer type 3 - looking upstream +const Int_t layer3o[9][11] = { + {823, 823, 823, 823, 823, 821, 821, 821, 821, 821, 821}, {823, 823, 823, 823, 823, 821, 821, 821, 821, 821, 821}, + {823, 823, 823, 723, 623, 621, 621, 721, 821, 821, 821}, {823, 823, 723, 623, 0, 0, 0, 621, 721, 821, 821}, + {803, 803, 703, 603, 0, 0, 0, 601, 701, 801, 801}, {803, 803, 703, 603, 0, 0, 0, 601, 701, 801, 801}, + {803, 803, 803, 703, 603, 601, 601, 701, 801, 801, 801}, {803, 803, 803, 803, 803, 801, 801, 801, 801, 801, 801}, + {803, 803, 803, 803, 803, 801, 801, 801, 801, 801, 801}}; +// number of modules: 90 +// Layer2 = 24 + 90; // v14a + + +// Parameters defining the layout of the different detector modules +const Int_t NofModuleTypes = 9; +const Int_t ModuleType[NofModuleTypes] = { + 0, 0, 0, 0, 1, 1, 1, 1, 2}; // 0 = small module, 1 = large module, 2 = bucharest small modules + +// FEB inclination angle +const Double_t feb_rotation_angle[NofModuleTypes] = { + 60, 90, 90, 80, 60, 60, 90, 90, 90}; // rotation around x-axis, 0 = vertical, 90 = horizontal +//const Double_t feb_rotation_angle[NofModuleTypes] = { 60, 90, 90, 80, 80, 90, 90, 90 }; // rotation around x-axis, 0 = vertical, 90 = horizontal +//const Double_t feb_rotation_angle[NofModuleTypes] = { 45, 45, 45, 45, 45, 45, 45, 45 }; // rotation around x-axis, 0 = vertical, 90 = horizontal + +// GBTx ROB definitions +//// v17d +//const Int_t RobsPerModule[NofModuleTypes] = { 4, 2, 2, 1, 2, 3, 2, 1 }; // number of GBTx ROBs on module +//const Int_t GbtxPerRob[NofModuleTypes] = {103,103,103,103,107,103,103,103 }; // number of GBTx ASICs on ROB +// +//const Int_t GbtxPerModule[NofModuleTypes] = { 12, 6, 6, 0, 0, 9, 6, 3 }; // for .geo.info - TODO: merge with above GbtxPerRob +//const Int_t RobTypeOnModule[NofModuleTypes]={ 3333, 33, 33, 0, 0,333, 33, 3 }; // for .geo.info - TODO: merge with above GbtxPerRob +// +// v17l - 96 cm +const Int_t RobsPerModule[NofModuleTypes] = {4, 2, 1, 1, 6, 6, 2, 2, 6}; // number of GBTx ROBs on module +const Int_t GbtxPerRob[NofModuleTypes] = {103, 103, 103, 103, 103, 103, 103, 103, 103}; // number of GBTx ASICs on ROB + +const Int_t GbtxPerModule[NofModuleTypes] = {12, 6, 3, 0, 18, + 18, 6, 6, 18}; // for .geo.info - TODO: merge with above GbtxPerRob +const Int_t RobTypeOnModule[NofModuleTypes] = { + 3333, 33, 3, 0, 333333, 333333, 33, 33, 333333}; // for .geo.info - TODO: merge with above GbtxPerRob + +//// v17c +//const Int_t RobsPerModule[NofModuleTypes] = { 4, 2, 1, 1, 2, 3, 2, 1 }; // number of GBTx ROBs on module +//const Int_t GbtxPerRob[NofModuleTypes] = {103,103,103,103,107,103,103,103 }; // number of GBTx ASICs on ROB +// +//const Int_t GbtxPerModule[NofModuleTypes] = { 12, 6, 3, 0, 0, 9, 6, 3 }; // for .geo.info - TODO: merge with above GbtxPerRob +//const Int_t RobTypeOnModule[NofModuleTypes]={ 3333, 33, 3, 0, 0,333, 33, 3 }; // for .geo.info - TODO: merge with above GbtxPerRob + +//// v17b +//const Int_t RobsPerModule[NofModuleTypes] = { 5, 3, 2, 1, 2, 3, 2, 1 }; // number of GBTx ROBs on module +//const Int_t GbtxPerRob[NofModuleTypes] = {103,103,103,103,107,103,103,103 }; // number of GBTx ASICs on ROB +// +//const Int_t GbtxPerModule[NofModuleTypes] = { 15, 9, 6, 0, 0, 9, 6, 3 }; // for .geo.info - TODO: merge with above GbtxPerRob +//const Int_t RobTypeOnModule[NofModuleTypes]={33333,333, 33, 0, 0,333, 33, 3 }; // for .geo.info - TODO: merge with above GbtxPerRob + +//v17a // GBTx ROB definitions +//v17a const Int_t RobsPerModule[NofModuleTypes] = { 3, 2, 1, 1, 2, 2, 1, 1 }; // number of GBTx ROBs on module +//v17a const Int_t GbtxPerRob[NofModuleTypes] = {105,105,105,103,107,105,105,103 }; // number of GBTx ASICs on ROB +//v17a +//v17a const Int_t GbtxPerModule[NofModuleTypes] = { 15, 10, 5, 0, 0, 10, 5, 3 }; // for .geo.info - TODO: merge with above GbtxPerRob +//v17a const Int_t RobTypeOnModule[NofModuleTypes]={555, 55, 5, 0, 0, 55, 5, 3 }; // for .geo.info - TODO: merge with above GbtxPerRob + +//const Int_t RobsPerModule[NofModuleTypes] = { 2, 2, 1, 1, 2, 2, 1, 1 }; // number of GBTx ROBs on module +//const Int_t GbtxPerRob[NofModuleTypes] = {107,105,105,103,107,105,105,103 }; // number of GBTx ASICs on ROB +//const Int_t GbtxPerModule[NofModuleTypes] = { 14, 8, 5, 0, 0, 10, 5, 3 }; // for .geo.info - TODO: merge with above GbtxPerRob +//const Int_t RobTypeOnModule[NofModuleTypes] = { 77, 53, 5, 0, 0, 55, 5, 3 }; // for .geo.info - TODO: merge with above GbtxPerRob + +// super density for type 1 modules - 2017 - 540 mm +//// v17d +//const Int_t FebsPerModule[NofModuleTypes] = { 8, 4, 4, 4, 12, 9, 6, 3 }; // number of FEBs on backside +//const Int_t AsicsPerFeb[NofModuleTypes] = {210,210,210,105,108,107,107,107 }; // %100 gives number of ASICs on FEB, /100 gives grouping + +// v17l - 96 cm +//const Int_t FebsPerModule[NofModuleTypes] = { 8, 4, 2, 4, 12, 8, 6, 4 }; // number of FEBs on backside +//const Int_t FebsPerModule[NofModuleTypes] = { 8, 4, 2, 4, 12, 8, 6, 2 }; // number of FEBs on backside +const Int_t FebsPerModule[NofModuleTypes] = {8, 4, 2, 4, 12, 12, 4, 4, 30}; // number of FEBs on backside +const Int_t AsicsPerFeb[NofModuleTypes] = {210, 210, 210, 105, 109, + 109, 109, 109, 6}; // %100 gives number of ASICs on FEB, /100 gives grouping + +//// v17c +//const Int_t FebsPerModule[NofModuleTypes] = { 8, 4, 2, 4, 12, 9, 6, 3 }; // number of FEBs on backside +//const Int_t AsicsPerFeb[NofModuleTypes] = {210,210,210,105,108,107,107,107 }; // %100 gives number of ASICs on FEB, /100 gives grouping + +//// v17b +//const Int_t FebsPerModule[NofModuleTypes] = { 10, 6, 4, 4, 12, 9, 6, 3 }; // number of FEBs on backside +//const Int_t AsicsPerFeb[NofModuleTypes] = {210,210,210,105,108,107,107,107 }; // %100 gives number of ASICs on FEB, /100 gives grouping +// v17a // super density for type 1 modules - 2017 - 540 mm +// v17a //const Int_t FebsPerModule[NofModuleTypes] = { 9, 5, 6, 4, 12, 8, 4, 3 }; // number of FEBs on backside +// v17a const Int_t FebsPerModule[NofModuleTypes] = { 9, 6, 3, 4, 12, 8, 4, 3 }; // number of FEBs on backside +// v17a const Int_t AsicsPerFeb[NofModuleTypes] = {210,210,210,105,108,108,108,108 }; // %100 gives number of ASICs on FEB, /100 gives grouping +//// ultimate density - 540 mm +//const Int_t FebsPerModule[NofModuleTypes] = { 6, 5, 6, 4, 12, 8, 4, 3 }; // number of FEBs on backside - reduced FEBs (64 ch ASICs) +//const Int_t AsicsPerFeb[NofModuleTypes] = {315,210,105,105,108,108,108,108 }; // %100 gives number of ASICs on FEB, /100 gives grouping +////const Int_t FebsPerModule[NofModuleTypes] = { 6, 5, 3, 2, 6, 3, 4, 3 }; // min number of FEBs // number of FEBs on backside - reduced FEBs (64 ch ASICs) +////const Int_t AsicsPerFeb[NofModuleTypes] = {315,210,210,210,216,216,108,108 }; // %100 gives number of ASICs on FEB, /100 gives grouping +////const Int_t AsicsPerFeb[NofModuleTypes] = {216,210,210,210,216,216,108,108 }; // %100 gives number of ASICs on FEB, /100 gives grouping +// +////// super density - 540 mm +//const Int_t FebsPerModule[NofModuleTypes] = { 9, 5, 6, 4, 12, 6, 4, 3 }; // light // number of FEBs on backside - reduced FEBs (64 ch ASICs) +//const Int_t AsicsPerFeb[NofModuleTypes] = {210,210,105,105,108,108,108,108 }; // %100 gives number of ASICs on FEB, /100 gives grouping +// +//// normal density - 540 mm +//const Int_t FebsPerModule[NofModuleTypes] = { 18, 10, 6, 4, 12, 6, 4, 3 }; // number of FEBs on backside (linked to pad layout) - mod4 = mod3, therefore same +//const Int_t AsicsPerFeb[NofModuleTypes] = {105,105,105,105,108,108,108,108 }; // %100 gives number of ASICs on FEB, /100 gives grouping + +// ultimate density - 570 mm +//const Int_t FebsPerModule[NofModuleTypes] = { 6, 5, 3, 2, 5, 3, 2, 1 }; // min number of FEBs // number of FEBs on backside - reduced FEBs (64 ch ASICs) +//const Int_t AsicsPerFeb[NofModuleTypes] = {216,210,210,210,216,216,216,216 }; // %100 gives number of ASICs on FEB, /100 gives grouping +// +//const Int_t FebsPerModule[NofModuleTypes] = { 6, 5, 3, 3, 10, 5, 3, 3 }; // min (6) module types // number of FEBs on backside - reduced FEBs (64 ch ASICs) +//const Int_t AsicsPerFeb[NofModuleTypes] = {216,210,210,210,108,108,108,108 }; // %100 gives number of ASICs on FEB, /100 gives grouping +//// super density - 570 mm +//const Int_t FebsPerModule[NofModuleTypes] = { 10, 5, 5, 5, 12, 6, 4, 3 }; // light // number of FEBs on backside - reduced FEBs (64 ch ASICs) +//const Int_t AsicsPerFeb[NofModuleTypes] = {210,210,105,105,108,108,108,108 }; // %100 gives number of ASICs on FEB, /100 gives grouping +// +//// normal density - 570 mm +//const Int_t FebsPerModule[NofModuleTypes] = { 19, 10, 5, 5, 12, 6, 4, 3 }; // number of FEBs on backside (linked to pad layout) - mod4 = mod3, therefore same +//const Int_t AsicsPerFeb[NofModuleTypes] = {105,105,105,105,108,108,108,108 }; // %100 gives number of ASICs on FEB, /100 gives grouping + + +/* TODO: activate connector grouping info below +// ultimate - grouping of pads to connectors +const Int_t RowsPerConnector[NofModuleTypes] = { 6, 4, 2, 2, 2, 2, 2, 2 }; +const Int_t ColsPerConnector[NofModuleTypes] = { 16, 16, 16, 16, 16, 16, 16, 16 }; +// super - grouping of pads to connectors +const Int_t RowsPerConnector[NofModuleTypes] = { 4, 4, 2, 2, 2, 2, 2, 2 }; +const Int_t ColsPerConnector[NofModuleTypes] = { 16, 16, 16, 16, 16, 16, 16, 16 }; +// normal - grouping of pads to connectors +const Int_t RowsPerConnector[NofModuleTypes] = { 2, 2, 2, 2, 2, 2, 2, 2 }; +const Int_t ColsPerConnector[NofModuleTypes] = { 16, 16, 16, 16, 16, 16, 16, 16 }; +*/ + + +const Double_t feb_z_offset = 0.1; // 1 mm - offset in z of FEBs to backpanel +const Double_t asic_offset = 0.1; // 1 mm - offset of ASICs to FEBs to avoid overlaps + +// ASIC parameters +Double_t asic_distance; + +//const Double_t FrameWidth[2] = { 1.5, 2.0 }; // Width of detector frames in cm +const Double_t FrameWidth[3] = {1.5, 1.5, 1.5}; // Width of detector frames in cm +// mini - production +const Double_t DetectorSizeX[3] = {57., 99., 57.}; // => 54 x 54 cm2 & 96 x 96 cm2 active area +const Double_t DetectorSizeY[3] = {57., 99., 57.}; // quadratic modules +// 108 cm const Double_t DetectorSizeX[2] = { 57., 111.}; // => 54 x 54 cm2 & 108 x 108 cm2 active area +// 108 cm const Double_t DetectorSizeY[2] = { 57., 111.}; // quadratic modules +//// default +//const Double_t DetectorSizeX[2] = { 60., 100.}; // => 57 x 57 cm2 & 96 x 96 cm2 active area +//const Double_t DetectorSizeY[2] = { 60., 100.}; // quadratic modules + +// Parameters tor the lattice grid reinforcing the entrance window +//const Double_t lattice_o_width[2] = { 1.5, 2.0 }; // Width of outer lattice frame in cm +const Double_t lattice_o_width[2] = {1.5, 1.5}; // Width of outer lattice frame in cm +const Double_t lattice_i_width[2] = {0.2, 0.2}; // { 0.4, 0.4 }; // Width of inner lattice frame in cm +// Thickness (in z) of lattice frames in cm - see below + +// statistics +Int_t ModuleStats[MaxLayers][NofModuleTypes] = {0}; + +// z - geometry of TRD modules +//const Double_t radiator_thickness = 35.0; // 35 cm thickness of radiator +const Double_t radiator_thickness = 30.0; // 30 cm thickness of radiator + shift pad plane to integer multiple of 1 mm +const Double_t radiator_position = -LayerThickness / 2. + radiator_thickness / 2.; + +//const Double_t lattice_thickness = 1.0; // 1.0; // 10 mm thick lattice frames +const Double_t lattice_thickness = 1.0 - 0.0025; // 0.9975; // 1.0; // 10 mm thick lattice frames +const Double_t lattice_position = radiator_position + radiator_thickness / 2. + lattice_thickness / 2.; + +const Double_t kapton_thickness = 0.0025; // 25 micron thickness of kapton +const Double_t kapton_position = lattice_position + lattice_thickness / 2. + kapton_thickness / 2.; + +const Double_t gas_thickness = 1.2; // 12 mm thickness of gas +const Double_t gas_position = kapton_position + kapton_thickness / 2. + gas_thickness / 2.; + +// frame thickness +const Double_t frame_thickness = gas_thickness; // frame covers gas volume: from kapton foil to pad plane +const Double_t frame_position = + -LayerThickness / 2. + radiator_thickness + lattice_thickness + kapton_thickness + frame_thickness / 2.; + +// pad plane +const Double_t padcopper_thickness = 0.0025; // 25 micron thickness of copper pads +const Double_t padcopper_position = gas_position + gas_thickness / 2. + padcopper_thickness / 2.; +const Double_t padplane_thickness = 0.0360; // 360 micron thickness of padplane +const Double_t padplane_position = padcopper_position + padcopper_thickness / 2. + padplane_thickness / 2.; + +// backpanel components +const Double_t carbon_thickness = 0.0190 * 2; // use 2 layers!! // 190 micron thickness for 1 layer of carbon fibers +const Double_t honeycomb_thickness = 2.3 - kapton_thickness - padcopper_thickness - padplane_thickness + - carbon_thickness; // ~ 2.3 mm thickness of honeycomb +const Double_t honeycomb_position = padplane_position + padplane_thickness / 2. + honeycomb_thickness / 2.; +const Double_t carbon_position = honeycomb_position + honeycomb_thickness / 2. + carbon_thickness / 2.; + +// aluminium thickness +const Double_t aluminium_thickness = 0.4; // crossbar of 1 x 1 cm at every module edge +const Double_t aluminium_width = 1.0; // crossbar of 1 x 1 cm at every module edge +const Double_t aluminium_position = carbon_position + carbon_thickness / 2. + aluminium_thickness / 2.; + +// power bus bars +const Double_t powerbar_thickness = 1.0; // 1 cm in z direction +const Double_t powerbar_width = 2.0; // 2 cm in x/y direction +const Double_t powerbar_position = aluminium_position + aluminium_thickness / 2. + powerbar_thickness / 2.; + +// readout boards +//const Double_t feb_width = 10.0; // width of FEBs in cm +const Double_t feb_width = 8.5; // width of FEBs in cm +const Double_t feb_thickness = 0.25; // light // 2.5 mm thickness of FEBs +const Double_t febvolume_position = aluminium_position + aluminium_thickness / 2. + feb_width / 2.; + +// ASIC parameters +const Double_t asic_thickness = 0.25; // 2.5 mm asic_thickness +const Double_t asic_width = 3.0; // 2.0; 1.0; // 1 cm + +// -------------- BUCHAREST PROTOTYPE SPECIFICS ---------------------------------- +// Frontpanel components +const Double_t carbonBu_thickness = 0.03; // 300 micron thickness for 1 layer of carbon fibers +const Double_t honeycombBu_thickness = 1.2; // 12 mm thickness of honeycomb +const Double_t WIN_Frame_thickness = 0.6; // entrance window framing 6x12 mm2 +const Double_t honeycombBu0_position = radiator_position + radiator_thickness / 2. + honeycombBu_thickness / 2.; +const Double_t carbonBu1_position = honeycombBu0_position + honeycombBu_thickness / 2. + carbonBu_thickness / 2.; +// Active volume +const Double_t gasBu_position = carbonBu1_position + carbonBu_thickness / 2. + gas_thickness / 2.; +// Pad plane +const Double_t padcopperBu_position = gasBu_position + gas_thickness / 2. + padcopper_thickness / 2.; +const Double_t padplaneBu_position = padcopperBu_position + padcopper_thickness / 2. + padplane_thickness / 2.; +// Backpanel components +const Double_t honeycombBu1_position = padplaneBu_position + padplane_thickness / 2. + honeycombBu_thickness / 2.; +// PCB +const Double_t glassFibre_thickness = 0.0270; // 300 microns overall PCB thickness +const Double_t cuCoating_thickness = 0.0030; +const Double_t glassFibre_position = honeycombBu1_position + honeycombBu_thickness / 2. + glassFibre_thickness / 2.; +const Double_t cuCoating_position = glassFibre_position + glassFibre_thickness / 2. + cuCoating_thickness / 2.; +//Frame around entrance window, active volume and exit window +const Double_t frameBu_thickness = 2 * carbonBu_thickness + honeycombBu_thickness + gas_thickness + padcopper_thickness + + padplane_thickness + honeycombBu_thickness + glassFibre_thickness + + cuCoating_thickness; +const Double_t frameBu_position = radiator_position + radiator_thickness / 2. + frameBu_thickness / 2.; + +// C-ROB3 parameters : GBTx ROBs +const Double_t rob_size_x = 20.0; // 13.0; // 130 mm +const Double_t rob_size_y = 9.0; // 4.5; // 45 mm +const Double_t rob_yoffset = 0.3; // offset wrt detector frame (on the detector plane) +const Double_t rob_zoffset = -7.5; // offset wrt entrace plane - center board +const Double_t rob_thickness = feb_thickness; +// GBTX parameters +const Double_t gbtx_thickness = 0.25; // 2.5 mm +const Double_t gbtx_width = 3.0; // 2.0; 1.0; // 1 cm +const Double_t gbtx_distance = 0.4; + + +// Names of the different used materials which are used to build the modules +// The materials are defined in the global media.geo file +const TString KeepingVolumeMedium = "air"; +const TString RadiatorVolumeMedium = "TRDpefoam20"; +const TString LatticeVolumeMedium = "TRDG10"; +const TString KaptonVolumeMedium = "TRDkapton"; +const TString GasVolumeMedium = "TRDgas"; +const TString PadCopperVolumeMedium = "TRDcopper"; +const TString PadPcbVolumeMedium = "TRDG10"; // todo - put correct FEB material here +const TString HoneycombVolumeMedium = "TRDaramide"; +const TString CarbonVolumeMedium = "TRDcarbon"; +const TString FebVolumeMedium = "TRDG10"; // todo - put correct FEB material here +const TString AsicVolumeMedium = "air"; // todo - put correct ASIC material here +const TString TextVolumeMedium = "air"; // leave as air +const TString FrameVolumeMedium = "TRDG10"; +const TString PowerBusVolumeMedium = "TRDcopper"; // power bus bars +const TString AluLegdeVolumeMedium = "aluminium"; // aluminium frame around backpanel +const TString AluminiumVolumeMedium = "aluminium"; +//const TString MylarVolumeMedium = "mylar"; +//const TString RadiatorVolumeMedium = "polypropylene"; +//const TString ElectronicsVolumeMedium = "goldcoatedcopper"; + + +// some global variables +TGeoManager* gGeoMan = NULL; // Pointer to TGeoManager instance +TGeoVolume* gModules[NofModuleTypes]; // Global storage for module types + +// Forward declarations +void create_materials_from_media_file(); +TGeoVolume* create_trd_module_type(Int_t moduleType); +TGeoVolume* create_trdi_module_type(Int_t moduleType = 2); +TGeoVolume* create_support_inner(); +void create_detector_layers(Int_t layer); +void create_power_bars_vertical(); +void create_power_bars_horizontal(); +void create_xtru_supports(); +void create_box_supports(); +void add_trd_labels(TGeoVolume*, TGeoVolume*, TGeoVolume*); +void create_mag_field_vector(); +void dump_info_file(); +void dump_digi_file(); + +void Create_TRD_Geometry_v18b() +{ + // declare TRD layer layout + if (setupid > 2) + for (Int_t i = 0; i < MaxLayers; i++) + ShowLayer[i] = 1; // show all layers + + // Load needed material definition from media.geo file + create_materials_from_media_file(); + + // Position the layers in z + for (Int_t iLayer = 1; iLayer < MaxLayers; iLayer++) + LayerPosition[iLayer] = + LayerPosition[iLayer - 1] + LayerThickness + LayerOffset[iLayer]; // add offset for extra gaps + + // Get the GeoManager for later usage + gGeoMan = (TGeoManager*) gROOT->FindObject("FAIRGeom"); + gGeoMan->SetVisLevel(10); + + // Create the top volume + TGeoBBox* topbox = new TGeoBBox("", 1000., 1000., 2000.); + TGeoVolume* top = new TGeoVolume("top", topbox, gGeoMan->GetMedium("air")); + gGeoMan->SetTopVolume(top); + + TGeoVolume* trd = new TGeoVolumeAssembly(geoVersion); + top->AddNode(trd, 1); + + for (Int_t iModule = 0; iModule < NofModuleTypes; iModule++) { + Int_t moduleType = iModule + 1; + if (moduleType < 9) gModules[iModule] = create_trd_module_type(moduleType); + else + gModules[iModule] = create_trdi_module_type(moduleType - 9); + } + + Int_t nLayer = 0; // active layer counter + for (Int_t iLayer = 0; iLayer < MaxLayers; iLayer++) { + // if ((iLayer != 0) && (iLayer != 3)) continue; // first layer only - comment later on + // if (iLayer != 0) continue; // first layer only - comment later on + if (ShowLayer[iLayer]) { + PlaneId[iLayer] = ++nLayer; + create_detector_layers(iLayer); + // printf("calling layer %2d\n",iLayer); + } + } + + // TODO: remove or comment out + // test PlaneId + printf("generated TRD layers: "); + for (Int_t iLayer = 0; iLayer < MaxLayers; iLayer++) + if (ShowLayer[iLayer]) printf(" %2d", PlaneId[iLayer]); + printf("\n"); + + if (IncludeSupports) { create_box_supports(); } + + if (IncludePowerbars) { + create_power_bars_vertical(); + create_power_bars_horizontal(); + } + + if (IncludeFieldVector) create_mag_field_vector(); + + gGeoMan->CloseGeometry(); + // gGeoMan->CheckOverlaps(0.001); + // gGeoMan->PrintOverlaps(); + gGeoMan->Test(); + + trd->Export(FileNameSim); // an alternative way of writing the trd volume + + TFile* outfile = new TFile(FileNameSim, "UPDATE"); + // TGeoTranslation* trd_placement = new TGeoTranslation("trd_trans", 0., 0., 0.); + TGeoTranslation* trd_placement = new TGeoTranslation("trd_trans", 0., 0., zfront[setupid]); + trd_placement->Write(); + outfile->Close(); + + outfile = new TFile(FileNameGeo, "RECREATE"); + gGeoMan->Write(); // use this is you want GeoManager format in the output + outfile->Close(); + + dump_info_file(); + dump_digi_file(); + + top->Draw("ogl"); + + //top->Raytrace(); + + // cout << "Press Return to exit" << endl; + // cin.get(); + // exit(); +} + + +//============================================================== +void dump_digi_file() +{ + TDatime datetime; // used to get timestamp + + const Double_t ActiveAreaX[3] = {DetectorSizeX[0] - 2 * FrameWidth[0], DetectorSizeX[1] - 2 * FrameWidth[1], + DetectorSizeX[2] - 2 * FrameWidth[2]}; + const Int_t NofSectors = 3; + // v17b + // const Int_t NofPadsInRow[2] = { 80, 112 }; // 7 // number of pads in rows + // const Int_t NofPadsInRow[2] = { 80, 128 }; // 8 // number of pads in rows + const Int_t NofPadsInRow[3] = {80, 144, 72}; // number of pads in rows + // const Int_t NofPadsInRow[2] = { 80, 160 }; // 10 // number of pads in rows + Int_t nrow = 0; // number of rows in module + + const Double_t PadHeightInSector[NofModuleTypes][NofSectors] = // pad height + {//v17b { 1.25, 1.50, 1.25 }, // module type 1 - 1.01 cm2 + //v17b { 2.25, 2.25, 2.25 }, // module type 2 - 1.52 cm2 + //v17b { 3.25, 3.50, 3.25 }, // module type 3 - 2.36 cm2 + + {1.50, 1.75, 1.50}, // module type 1 - 1.18 cm2 + {3.25, 3.50, 3.25}, // module type 2 - 2.36 cm2 + {6.75, 6.75, 6.75}, // module type 3 - 4.56 cm2 + {6.75, 6.75, 6.75}, // module type 4 - + + // 108 cm { 2.25, 2.25, 2.25 }, // module type 5 - + // 108 cm { 4.50, 4.50, 4.50 }, // module type 6 - 4.52 cm2 + // 108 cm { 9.00, 9.00, 9.00 }, // module type 7 - 6.37 cm2 + // 108 cm { 18.00, 18.00, 18.00 } }; // module type 8 - 12.73 cm2 + + {4.00, 4.00, 4.00}, // module type 5 - 2.67 cm2 + {6.00, 6.00, 6.00}, // module type 6 - 4.00 cm2 + {12.00, 12.00, 12.00}, // module type 7 - 8.00 cm2 + {24.00, 24.00, 24.00}, // module type 8 - 16.00 cm2 + + // { 3.75, 4.00, 3.75 }, // module type 5 - + // { 5.00, 5.50, 5.00 }, // module type 6 - 4.52 cm2 + // { 7.50, 7.75, 7.50 }, // module type 7 - 6.37 cm2 + // { 15.25, 15.50, 15.25 } }; // module type 8 - 12.73 cm2 + {2.70, 2.70, 2.70}}; // module type 9 - triangular pads H=26.8+0.2 mm, W=7.3+0.2 mm + + const Int_t NofRowsInSector[NofModuleTypes][NofSectors] = // number of rows per sector + { //v17b { 12, 16, 12 }, // module type 1 + //v17b { 8, 8, 8 }, // module type 2 + //v17b { 4, 8, 4 }, // module type 3 + + {4, 24, 4}, // module type 1 + {4, 8, 4}, // module type 2 + {2, 4, 2}, // module type 3 + {2, 4, 2}, // module type 4 + + {8, 8, 8}, // module type 5 + {6, 4, 6}, // module type 6 + {2, 4, 2}, // module type 7 + {1, 2, 1}, // module type 8 + + // { 8, 8, 8 }, // module type 5 + // { 4, 8, 4 }, // module type 6 + // { 2, 8, 2 }, // module type 7 + // { 2, 2, 2 } }; // module type 8 + {2, 16, 2}}; // module type 9 + + // v17a const Int_t NofPadsInRow[2] = { 80, 128 }; // number of pads in rows + // v17a Int_t nrow = 0; // number of rows in module + // v17a + // v17a const Double_t PadHeightInSector[NofModuleTypes][NofSectors] = // pad height + // v17a { { 1.50, 1.50, 1.50 }, // module type 1 - 1.01 cm2 + // v17a { 2.25, 2.25, 2.25 }, // module type 2 - 1.52 cm2 + // v17a // { 2.75, 2.50, 2.75 }, // module type 2 - 1.86 cm2 + // v17a { 4.50, 4.50, 4.50 }, // module type 3 - 3.04 cm2 + // v17a { 6.75, 6.75, 6.75 }, // module type 4 - 4.56 cm2 + // v17a + // v17a { 3.75, 4.00, 3.75 }, // module type 5 - 2.84 cm2 + // v17a { 5.75, 5.75, 5.75 }, // module type 6 - 4.13 cm2 + // v17a { 11.50, 11.50, 11.50 }, // module type 7 - 8.26 cm2 + // v17a { 15.25, 15.50, 15.25 } }; // module type 8 - 11.14 cm2 + // v17a // { 7.50, 7.75, 7.50 }, // module type 6 - 5.51 cm2 + // v17a // { 5.50, 5.75, 5.50 }, // module type 6 - 4.09 cm2 + // v17a // { 11.25, 11.50, 11.25 }, // module type 7 - 8.18 cm2 + // v17a + // v17a const Int_t NofRowsInSector[NofModuleTypes][NofSectors] = // number of rows per sector + // v17a { { 12, 12, 12 }, // module type 1 + // v17a { 8, 8, 8 }, // module type 2 + // v17a // { 8, 4, 8 }, // module type 2 + // v17a { 4, 4, 4 }, // module type 3 + // v17a { 2, 4, 2 }, // module type 4 + // v17a + // v17a { 8, 8, 8 }, // module type 5 + // v17a { 4, 8, 4 }, // module type 6 + // v17a { 2, 4, 2 }, // module type 7 + // v17a { 2, 2, 2 } }; // module type 8 + // v17a // { 10, 4, 10 }, // module type 5 + // v17a // { 4, 4, 4 }, // module type 6 + // v17a // { 2, 12, 2 }, // module type 6 + // v17a // { 2, 4, 2 }, // module type 7 + // v17a // { 2, 2, 2 } }; // module type 8 + // v17a + + Double_t HeightOfSector[NofModuleTypes][NofSectors]; + Double_t PadWidth[NofModuleTypes]; + + // calculate pad width + for (Int_t im = 0; im < NofModuleTypes; im++) + PadWidth[im] = ActiveAreaX[ModuleType[im]] / NofPadsInRow[ModuleType[im]]; + + // calculate height of sectors + for (Int_t im = 0; im < NofModuleTypes; im++) + for (Int_t is = 0; is < NofSectors; is++) + HeightOfSector[im][is] = NofRowsInSector[im][is] * PadHeightInSector[im][is]; + + // check, if the entire module size is covered by pads + for (Int_t im = 0; im < NofModuleTypes; im++) + if (ActiveAreaX[ModuleType[im]] - (HeightOfSector[im][0] + HeightOfSector[im][1] + HeightOfSector[im][2]) != 0) { + printf("WARNING: sector size does not add up to module size for module " + "type %d\n", + im + 1); + printf("%.2f = %.2f + %.2f + %.2f\n", ActiveAreaX[ModuleType[im]], HeightOfSector[im][0], HeightOfSector[im][1], + HeightOfSector[im][2]); + exit(1); + } + + //============================================================== + + printf("writing trd pad information file: %s\n", FileNamePads.Data()); + + FILE* ifile; + ifile = fopen(FileNamePads.Data(), "w"); + + if (ifile == NULL) { + printf("error opening %s\n", FileNamePads.Data()); + exit(1); + } + + fprintf(ifile, "//\n"); + fprintf(ifile, "// TRD pad layout for geometry %s\n", tagVersion.Data()); + fprintf(ifile, "//\n"); + fprintf(ifile, "// automatically generated by Create_TRD_Geometry_%s%s.C\n", tagVersion.Data(), subVersion.Data()); + fprintf(ifile, "// created %d\n", datetime.GetDate()); + fprintf(ifile, "//\n"); + + fprintf(ifile, "\n"); + fprintf(ifile, "#ifndef CBMTRDPADS_H\n"); + fprintf(ifile, "#define CBMTRDPADS_H\n"); + fprintf(ifile, "\n"); + fprintf(ifile, "Int_t fst1_sect_count = 3;\n"); + fprintf(ifile, "// array of pad geometries in the TRD (trd1mod[1-%d])\n", NofModuleTypes); + fprintf(ifile, "// %d modules // 3 sectors // 4 values \n", NofModuleTypes); + fprintf(ifile, "Float_t fst1_pad_type[%d][3][4] = \n", NofModuleTypes); + //fprintf(ifile,"Double_t fst1_pad_type[8][3][4] = \n"); + fprintf(ifile, " \n"); + + for (Int_t im = 0; im < NofModuleTypes; im++) { + if (im + 1 == 5) fprintf(ifile, "//---\n\n"); + fprintf(ifile, "// module type %d\n", im + 1); + + // number of pads + nrow = 0; // reset number of pad rows to 0 + for (Int_t is = 0; is < NofSectors; is++) + nrow += HeightOfSector[im][is] / PadHeightInSector[im][is]; // add number of rows in this sector + fprintf(ifile, "// number of pads: %3d x %2d = %4d\n", NofPadsInRow[ModuleType[im]], nrow, + NofPadsInRow[ModuleType[im]] * nrow); + + // pad size + fprintf(ifile, "// pad size sector 1: %5.2f cm x %5.2f cm = %5.2f cm2\n", PadWidth[im], PadHeightInSector[im][1], + PadWidth[im] * PadHeightInSector[im][1]); + fprintf(ifile, "// pad size sector 0: %5.2f cm x %5.2f cm = %5.2f cm2\n", PadWidth[im], PadHeightInSector[im][0], + PadWidth[im] * PadHeightInSector[im][0]); + + for (Int_t is = 0; is < NofSectors; is++) { + if ((im == 0) && (is == 0)) fprintf(ifile, " { { "); + else if (is == 0) + fprintf(ifile, " { "); + else + fprintf(ifile, " "); + + fprintf(ifile, "{ %.1f, %5.2f, %.1f/%3d, %5.2f }", ActiveAreaX[ModuleType[im]], HeightOfSector[im][is], + ActiveAreaX[ModuleType[im]], NofPadsInRow[ModuleType[im]], PadHeightInSector[im][is]); + + if ((im == NofModuleTypes - 1) && (is == 2)) fprintf(ifile, " } };"); + else if (is == 2) + fprintf(ifile, " },"); + else + fprintf(ifile, ","); + + fprintf(ifile, "\n"); + } + + fprintf(ifile, "\n"); + } + + fprintf(ifile, "#endif\n"); + + // Int_t im = 0; + // fprintf(ifile,"// module type %d \n", im+1); + // fprintf(ifile," { { { %.1f, %5.2f, %.1f/%3d, %5.2f }, \n", ActiveAreaX[ModuleType[im]], HeightOfSector[im][0], ActiveAreaX[ModuleType[im]], NofPadsInRow[ModuleType[im]], PadHeightInSector[im][0]); + // fprintf(ifile," { %.1f, %5.2f, %.1f/%3d, %5.2f }, \n", ActiveAreaX[ModuleType[im]], HeightOfSector[im][1], ActiveAreaX[ModuleType[im]], NofPadsInRow[ModuleType[im]], PadHeightInSector[im][1]); + // fprintf(ifile," { %.1f, %5.2f, %.1f/%3d, %5.2f } }, \n", ActiveAreaX[ModuleType[im]], HeightOfSector[im][2], ActiveAreaX[ModuleType[im]], NofPadsInRow[ModuleType[im]], PadHeightInSector[im][2]); + // fprintf(ifile,"\n"); + // + // for (Int_t im = 1; im < NofModuleTypes-1; im++) + // { + // fprintf(ifile,"// module type %d \n", im+1); + // fprintf(ifile," { { %.1f, %5.2f, %.1f/%3d, %5.2f }, \n", ActiveAreaX[ModuleType[im]], HeightOfSector[im][0], ActiveAreaX[ModuleType[im]], NofPadsInRow[ModuleType[im]], PadHeightInSector[im][0]); + // fprintf(ifile," { %.1f, %5.2f, %.1f/%3d, %5.2f }, \n", ActiveAreaX[ModuleType[im]], HeightOfSector[im][1], ActiveAreaX[ModuleType[im]], NofPadsInRow[ModuleType[im]], PadHeightInSector[im][1]); + // fprintf(ifile," { %.1f, %5.2f, %.1f/%3d, %5.2f } }, \n", ActiveAreaX[ModuleType[im]], HeightOfSector[im][2], ActiveAreaX[ModuleType[im]], NofPadsInRow[ModuleType[im]], PadHeightInSector[im][2]); + // fprintf(ifile,"\n"); + // } + // + // Int_t im = 7; + // fprintf(ifile,"// module type %d \n", im+1); + // fprintf(ifile," { { %.1f, %5.2f, %.1f/%3d, %5.2f }, \n", ActiveAreaX[ModuleType[im]], HeightOfSector[im][0], ActiveAreaX[ModuleType[im]], NofPadsInRow[ModuleType[im]], PadHeightInSector[im][0]); + // fprintf(ifile," { %.1f, %5.2f, %.1f/%3d, %5.2f }, \n", ActiveAreaX[ModuleType[im]], HeightOfSector[im][1], ActiveAreaX[ModuleType[im]], NofPadsInRow[ModuleType[im]], PadHeightInSector[im][1]); + // fprintf(ifile," { %.1f, %5.2f, %.1f/%3d, %5.2f } } };\n", ActiveAreaX[ModuleType[im]], HeightOfSector[im][2], ActiveAreaX[ModuleType[im]], NofPadsInRow[ModuleType[im]], PadHeightInSector[im][2]); + // fprintf(ifile,"\n"); + + fclose(ifile); +} + + +void dump_info_file() +{ + TDatime datetime; // used to get timestamp + + Double_t z_first_layer = 2000; // z position of first layer (front) + Double_t z_last_layer = 0; // z position of last layer (front) + + Double_t xangle; // horizontal angle + Double_t yangle; // vertical angle + Double_t yangleo; // vertical angle for outer modules + + Double_t total_surface = 0; // total surface + Double_t total_actarea = 0; // total active area + + Int_t channels_per_module[NofModuleTypes + 1] = {0}; // number of channels per module + Int_t channels_per_feb[NofModuleTypes + 1] = {0}; // number of channels per feb + Int_t asics_per_module[NofModuleTypes + 1] = {0}; // number of asics per module + + Int_t total_modules[NofModuleTypes + 1] = {0}; // total number of modules + Int_t total_febs[NofModuleTypes + 1] = {0}; // total number of febs + Int_t total_asics[NofModuleTypes + 1] = {0}; // total number of asics + Int_t total_gbtx[NofModuleTypes + 1] = {0}; // total number of gbtx + Int_t total_rob3[NofModuleTypes + 1] = {0}; // total number of gbtx rob3 + Int_t total_rob5[NofModuleTypes + 1] = {0}; // total number of gbtx rob5 + Int_t total_rob7[NofModuleTypes + 1] = {0}; // total number of gbtx rob7 + Int_t total_channels[NofModuleTypes + 1] = {0}; // total number of channels + + Int_t total_channels_u = 0; // total number of ultimate channels + Int_t total_channels_s = 0; // total number of super channels + Int_t total_channels_r = 0; // total number of regular channels + Int_t total_channels_f = 0; // total number of FASP channels + + printf("writing summary information file: %s\n", FileNameInfo.Data()); + + FILE* ifile; + ifile = fopen(FileNameInfo.Data(), "w"); + + if (ifile == NULL) { + printf("error opening %s\n", FileNameInfo.Data()); + exit(1); + } + + fprintf(ifile, "#\n## %s information file\n#\n\n", geoVersion.Data()); + + fprintf(ifile, "# created %d\n\n", datetime.GetDate()); + + // determine first and last TRD layer + for (Int_t iLayer = 0; iLayer < MaxLayers; iLayer++) { + if (ShowLayer[iLayer]) { + if (z_first_layer > LayerPosition[iLayer]) z_first_layer = LayerPosition[iLayer]; + if (z_last_layer < LayerPosition[iLayer]) z_last_layer = LayerPosition[iLayer]; + } + } + + fprintf(ifile, "# position\n"); + // Show position of TRD + fprintf(ifile, "%4f cm z-front position of TRD in hadron setup\n", zfront[0]); + fprintf(ifile, "%4f cm z-front position of TRD in electron setup\n", zfront[1]); + fprintf(ifile, "%4f cm z-front position of TRD in muon setup\n", zfront[2]); + fprintf(ifile, "\n"); + + // fprintf(ifile, "# envelope\n"); + fprintf(ifile, "# detector thickness\n"); + // Show extension of TRD + // fprintf(ifile, "%4f cm start of TRD (z)\n", z_first_layer); + fprintf(ifile, "%4f cm end of TRD (z)\n", z_last_layer + LayerThickness); + fprintf(ifile, "\n"); + + // Layer thickness + fprintf(ifile, "# layer thickness\n"); + fprintf(ifile, "%4f cm per single layer (z)\n", LayerThickness); + fprintf(ifile, "\n"); + + // Show extra gaps + fprintf(ifile, "# extra gaps\n "); + for (Int_t iLayer = 0; iLayer < MaxLayers; iLayer++) + if (ShowLayer[iLayer]) fprintf(ifile, "%3f ", LayerOffset[iLayer]); + fprintf(ifile, " extra gaps in z (cm)\n"); + fprintf(ifile, "\n"); + + // Show layer flags + fprintf(ifile, "# generated TRD layers\n "); + for (Int_t iLayer = 0; iLayer < MaxLayers; iLayer++) + if (ShowLayer[iLayer]) fprintf(ifile, "%2d ", PlaneId[iLayer]); + fprintf(ifile, " planeID\n"); + fprintf(ifile, "\n"); + + // Dimensions in x + fprintf(ifile, "# dimensions in x\n"); + for (Int_t iLayer = 0; iLayer < MaxLayers; iLayer++) + if (ShowLayer[iLayer]) { + if (PlaneId[iLayer] < 5) + fprintf(ifile, "%5f cm to %5f cm x-dimension of layer %2d\n", + -(2.0 * DetectorSizeX[0] + 2.0 * DetectorSizeX[1]), 2.0 * DetectorSizeX[0] + 2.0 * DetectorSizeX[1], + PlaneId[iLayer]); + else { + if (PlaneId[iLayer] < 9) + fprintf(ifile, "%5f cm to %5f cm x-dimension of layer %2d\n", -4.5 * DetectorSizeX[1], 4.5 * DetectorSizeX[1], + PlaneId[iLayer]); + else + fprintf(ifile, "%5f cm to %5f cm x-dimension of layer %2d\n", -5.5 * DetectorSizeX[1], 5.5 * DetectorSizeX[1], + PlaneId[iLayer]); + } + } + fprintf(ifile, "\n"); + + // Dimensions in y + fprintf(ifile, "# dimensions in y inner modules\n"); + for (Int_t iLayer = 0; iLayer < MaxLayers; iLayer++) + if (ShowLayer[iLayer]) { + if (PlaneId[iLayer] < 5) + fprintf(ifile, "%5f cm to %5f cm y-dimension of layer %2d\n", -4.5 * DetectorSizeY[0], 4.5 * DetectorSizeY[0], + PlaneId[iLayer]); + else { + if (PlaneId[iLayer] < 9) + fprintf(ifile, "%5f cm to %5f cm y-dimension of layer %2d\n", -3.5 * DetectorSizeY[1], 3.5 * DetectorSizeY[1], + PlaneId[iLayer]); + else + fprintf(ifile, "%5f cm to %5f cm y-dimension of layer %2d\n", -4.5 * DetectorSizeY[1], 4.5 * DetectorSizeY[1], + PlaneId[iLayer]); + } + } + fprintf(ifile, "\n"); + + // Dimensions in y + fprintf(ifile, "# dimensions in y outer modules\n"); + for (Int_t iLayer = 0; iLayer < MaxLayers; iLayer++) + if (ShowLayer[iLayer]) { + if (PlaneId[iLayer] < 5) + fprintf(ifile, "%5f cm to %5f cm y-dimension of layer %2d\n", -2.5 * DetectorSizeY[1], 2.5 * DetectorSizeY[1], + PlaneId[iLayer]); + } + fprintf(ifile, "\n"); + + // angles + fprintf(ifile, "# angles of acceptance for inner + outer modules\n"); + + for (Int_t iLayer = 0; iLayer < MaxLayers; iLayer++) + if (ShowLayer[iLayer]) { + if (iLayer < 4) { + // fprintf(ifile,"y %10.4f cm x %10.4f cm\n", 2.5 * DetectorSizeY[1], 3.5 * DetectorSizeX[1]); + yangle = atan(4.5 * DetectorSizeY[0] + / (zfront[setupid] + LayerPosition[iLayer] + LayerThickness / 2. + padplane_position)) + * 180. / acos(-1.); + yangleo = atan(2.5 * DetectorSizeY[1] + / (zfront[setupid] + LayerPosition[iLayer] + LayerThickness / 2. + padplane_position)) + * 180. / acos(-1.); + xangle = atan((2.0 * DetectorSizeX[0] + 2.0 * DetectorSizeX[1]) + / (zfront[setupid] + LayerPosition[iLayer] + LayerThickness / 2. + padplane_position)) + * 180. / acos(-1.); + } + if ((iLayer >= 4) && (iLayer < 8)) { + // fprintf(ifile,"y %10.4f cm x %10.4f cm\n", 3.5 * DetectorSizeY[1], 4.5 * DetectorSizeX[1]); + yangle = atan(3.5 * DetectorSizeY[1] / (LayerPosition[iLayer] + LayerThickness / 2. + padplane_position)) * 180. + / acos(-1.); + xangle = atan(4.5 * DetectorSizeX[1] / (LayerPosition[iLayer] + LayerThickness / 2. + padplane_position)) * 180. + / acos(-1.); + } + if ((iLayer >= 8) && (iLayer < 10)) { + // fprintf(ifile,"y %10.4f cm x %10.4f cm\n", 4.5 * DetectorSizeY[1], 5.5 * DetectorSizeX[1]); + yangle = atan(4.5 * DetectorSizeY[1] / (LayerPosition[iLayer] + LayerThickness / 2. + padplane_position)) * 180. + / acos(-1.); + xangle = atan(5.5 * DetectorSizeX[1] / (LayerPosition[iLayer] + LayerThickness / 2. + padplane_position)) * 180. + / acos(-1.); + } + fprintf(ifile, "vi: %5.2f deg, vo: %5.2f deg, h: %5.2f deg - vertical/horizontal - layer %2d\n", yangle, yangleo, + xangle, PlaneId[iLayer]); + } + fprintf(ifile, "\n"); + + // aperture + fprintf(ifile, "# inner aperture\n"); + + for (Int_t iLayer = 0; iLayer < MaxLayers; iLayer++) + if (ShowLayer[iLayer]) { + if (iLayer < 4) { + // fprintf(ifile,"y %10.4f cm x %10.4f cm\n", 2.5 * DetectorSizeY[1], 3.5 * DetectorSizeX[1]); + yangle = atan(0.5 * DetectorSizeY[0] + / (zfront[setupid] + LayerPosition[iLayer] + LayerThickness / 2. + padplane_position)) + * 180. / acos(-1.); + xangle = atan(1.0 * DetectorSizeX[0] + / (zfront[setupid] + LayerPosition[iLayer] + LayerThickness / 2. + padplane_position)) + * 180. / acos(-1.); + } + if ((iLayer >= 4) && (iLayer < 8)) { + // fprintf(ifile,"y %10.4f cm x %10.4f cm\n", 3.5 * DetectorSizeY[1], 4.5 * DetectorSizeX[1]); + yangle = atan(0.5 * DetectorSizeY[0] + / (zfront[setupid] + LayerPosition[iLayer] + LayerThickness / 2. + padplane_position)) + * 180. / acos(-1.); + xangle = atan(0.5 * DetectorSizeX[0] + / (zfront[setupid] + LayerPosition[iLayer] + LayerThickness / 2. + padplane_position)) + * 180. / acos(-1.); + } + if ((iLayer >= 8) && (iLayer < 10)) { + // fprintf(ifile,"y %10.4f cm x %10.4f cm\n", 4.5 * DetectorSizeY[1], 5.5 * DetectorSizeX[1]); + yangle = atan(0.5 * DetectorSizeY[0] + / (zfront[setupid] + LayerPosition[iLayer] + LayerThickness / 2. + padplane_position)) + * 180. / acos(-1.); + xangle = atan(0.5 * DetectorSizeX[0] + / (zfront[setupid] + LayerPosition[iLayer] + LayerThickness / 2. + padplane_position)) + * 180. / acos(-1.); + } + fprintf(ifile, "v: %5.2f deg, h: %5.2f deg - vertical/horizontal - layer %2d\n", yangle, xangle, PlaneId[iLayer]); + } + fprintf(ifile, "\n"); + + // Show layer positions + fprintf(ifile, "# z-positions of layer front\n"); + for (Int_t iLayer = 0; iLayer < MaxLayers; iLayer++) { + if (ShowLayer[iLayer]) + fprintf(ifile, "%7.2f cm z-position of layer %2d\n", LayerPosition[iLayer], PlaneId[iLayer]); + } + fprintf(ifile, "\n"); + + // flags + fprintf(ifile, "# flags\n"); + + fprintf(ifile, "support structure is : "); + if (!IncludeSupports) fprintf(ifile, "NOT "); + fprintf(ifile, "included\n"); + + fprintf(ifile, "radiator is : "); + if (!IncludeRadiator) fprintf(ifile, "NOT "); + fprintf(ifile, "included\n"); + + fprintf(ifile, "lattice grid is : "); + if (!IncludeLattice) fprintf(ifile, "NOT "); + fprintf(ifile, "included\n"); + + fprintf(ifile, "kapton window is : "); + if (!IncludeKaptonFoil) fprintf(ifile, "NOT "); + fprintf(ifile, "included\n"); + + fprintf(ifile, "gas frame is : "); + if (!IncludeGasFrame) fprintf(ifile, "NOT "); + fprintf(ifile, "included\n"); + + fprintf(ifile, "padplane is : "); + if (!IncludePadplane) fprintf(ifile, "NOT "); + fprintf(ifile, "included\n"); + + fprintf(ifile, "backpanel is : "); + if (!IncludeBackpanel) fprintf(ifile, "NOT "); + fprintf(ifile, "included\n"); + + fprintf(ifile, "Aluminium ledge is : "); + if (!IncludeAluLedge) fprintf(ifile, "NOT "); + fprintf(ifile, "included\n"); + + fprintf(ifile, "Power bus bars are : "); + if (!IncludePowerbars) fprintf(ifile, "NOT "); + fprintf(ifile, "included\n"); + + fprintf(ifile, "asics are : "); + if (!IncludeAsics) fprintf(ifile, "NOT "); + fprintf(ifile, "included\n"); + + fprintf(ifile, "front-end boards are : "); + if (!IncludeFebs) fprintf(ifile, "NOT "); + fprintf(ifile, "included\n"); + + fprintf(ifile, "GBTX readout boards are : "); + if (!IncludeRobs) fprintf(ifile, "NOT "); + fprintf(ifile, "included\n"); + + fprintf(ifile, "\n"); + + + // module statistics + // fprintf(ifile,"#\n## modules\n#\n\n"); + // fprintf(ifile,"number of modules per type and layer:\n"); + fprintf(ifile, "# modules\n"); + + for (Int_t iModule = 1; iModule <= NofModuleTypes; iModule++) + fprintf(ifile, " mod%1d", iModule); + fprintf(ifile, " total"); + + fprintf(ifile, "\n------------------------------------------------------------------" + "---------------\n"); + for (Int_t iLayer = 0; iLayer < MaxLayers; iLayer++) + if (ShowLayer[iLayer]) { + for (Int_t iModule = 0; iModule < NofModuleTypes; iModule++) { + fprintf(ifile, " %8d", ModuleStats[iLayer][iModule]); + total_modules[iModule] += ModuleStats[iLayer][iModule]; // sum up modules across layers + } + fprintf(ifile, " layer %2d\n", PlaneId[iLayer]); + } + fprintf(ifile, "\n------------------------------------------------------------------" + "---------------\n"); + + // total statistics + for (Int_t iModule = 0; iModule < NofModuleTypes; iModule++) { + fprintf(ifile, " %8d", total_modules[iModule]); + total_modules[NofModuleTypes] += total_modules[iModule]; + } + fprintf(ifile, " %8d", total_modules[NofModuleTypes]); + fprintf(ifile, " number of modules\n"); + + //------------------------------------------------------------------------------ + + // number of FEBs + // fprintf(ifile,"\n#\n## febs\n#\n\n"); + fprintf(ifile, "# febs\n"); + + fprintf(ifile, " "); + for (Int_t iModule = 0; iModule < NofModuleTypes; iModule++) { + if ((AsicsPerFeb[iModule] / 100) == 3) fprintf(ifile, "%8du", FebsPerModule[iModule]); + else if ((AsicsPerFeb[iModule] / 100) == 2) + fprintf(ifile, "%8ds", FebsPerModule[iModule]); + else + fprintf(ifile, "%8d ", FebsPerModule[iModule]); + } + fprintf(ifile, " FEBs per module\n"); + + // FEB total per type + total_febs[NofModuleTypes] = 0; // reset sum to 0 + fprintf(ifile, " "); + for (Int_t iModule = 0; iModule < NofModuleTypes; iModule++) { + if ((AsicsPerFeb[iModule] / 100) == 3) { + total_febs[iModule] = total_modules[iModule] * FebsPerModule[iModule]; + fprintf(ifile, "%8du", total_febs[iModule]); + total_febs[NofModuleTypes] += total_febs[iModule]; + } + else + fprintf(ifile, " "); + } + fprintf(ifile, "%8d", total_febs[NofModuleTypes]); + fprintf(ifile, " ultimate FEBs\n"); + + // FEB total per type + total_febs[NofModuleTypes] = 0; // reset sum to 0 + fprintf(ifile, " "); + for (Int_t iModule = 0; iModule < NofModuleTypes; iModule++) { + if ((AsicsPerFeb[iModule] / 100) == 2) { + total_febs[iModule] = total_modules[iModule] * FebsPerModule[iModule]; + fprintf(ifile, "%8ds", total_febs[iModule]); + total_febs[NofModuleTypes] += total_febs[iModule]; + } + else + fprintf(ifile, " "); + } + fprintf(ifile, "%8d", total_febs[NofModuleTypes]); + fprintf(ifile, " super FEBs\n"); + + // FEB total per type + total_febs[NofModuleTypes] = 0; // reset sum to 0 + fprintf(ifile, " "); + for (Int_t iModule = 0; iModule < NofModuleTypes; iModule++) { + if ((AsicsPerFeb[iModule] / 100) == 1) { + total_febs[iModule] = total_modules[iModule] * FebsPerModule[iModule]; + fprintf(ifile, "%8d ", total_febs[iModule]); + total_febs[NofModuleTypes] += total_febs[iModule]; + } + else + fprintf(ifile, " "); + } + fprintf(ifile, "%8d", total_febs[NofModuleTypes]); + fprintf(ifile, " regular FEBs\n"); + + // FEB total over all types + total_febs[NofModuleTypes] = 0; // reset sum to 0 + for (Int_t iModule = 0; iModule < NofModuleTypes; iModule++) { + total_febs[iModule] = total_modules[iModule] * FebsPerModule[iModule]; + fprintf(ifile, " %8d", total_febs[iModule]); + total_febs[NofModuleTypes] += total_febs[iModule]; + } + fprintf(ifile, " %8d", total_febs[NofModuleTypes]); + fprintf(ifile, " number of FEBs\n"); + + //------------------------------------------------------------------------------ + + // number of ASICs + // fprintf(ifile,"\n#\n## asics\n#\n\n"); + fprintf(ifile, "# asics\n"); + + for (Int_t iModule = 0; iModule < NofModuleTypes; iModule++) { + fprintf(ifile, " %8d", AsicsPerFeb[iModule] % 100); + } + fprintf(ifile, " ASICs per FEB\n"); + + // ASICs per module + for (Int_t iModule = 0; iModule < NofModuleTypes; iModule++) { + asics_per_module[iModule] = FebsPerModule[iModule] * (AsicsPerFeb[iModule] % 100); + fprintf(ifile, " %8d", asics_per_module[iModule]); + } + fprintf(ifile, " ASICs per module\n"); + + // ASICs per module type + for (Int_t iModule = 0; iModule < NofModuleTypes; iModule++) { + total_asics[iModule] = total_febs[iModule] * (AsicsPerFeb[iModule] % 100); + fprintf(ifile, " %8d", total_asics[iModule]); + total_asics[NofModuleTypes] += total_asics[iModule]; + } + fprintf(ifile, " %8d", total_asics[NofModuleTypes]); + fprintf(ifile, " number of ASICs\n"); + + //------------------------------------------------------------------------------ + + // number of GBTXs + // fprintf(ifile,"\n#\n## asics\n#\n\n"); + fprintf(ifile, "# gbtx\n"); + + for (Int_t iModule = 0; iModule < NofModuleTypes; iModule++) { + fprintf(ifile, " %8d", GbtxPerModule[iModule]); + } + fprintf(ifile, " GBTXs per module\n"); + + // GBTXs per module type + for (Int_t iModule = 0; iModule < NofModuleTypes; iModule++) { + total_gbtx[iModule] = total_modules[iModule] * GbtxPerModule[iModule]; + fprintf(ifile, " %8d", total_gbtx[iModule]); + total_gbtx[NofModuleTypes] += total_gbtx[iModule]; + } + fprintf(ifile, " %8d", total_gbtx[NofModuleTypes]); + fprintf(ifile, " number of GBTXs\n"); + + // GBTX ROB types per module type + for (Int_t iModule = 0; iModule < NofModuleTypes; iModule++) { + fprintf(ifile, " %8d", RobTypeOnModule[iModule]); + } + fprintf(ifile, " GBTX ROB types on module\n"); + + for (Int_t iModule = 0; iModule < NofModuleTypes; iModule++) { + if ((RobTypeOnModule[iModule] % 10) == 7) total_rob7[iModule]++; + if ((RobTypeOnModule[iModule] / 10 % 10) == 7) total_rob7[iModule]++; + if ((RobTypeOnModule[iModule] / 100) == 7) total_rob7[iModule]++; + + if ((RobTypeOnModule[iModule] % 10) == 5) total_rob5[iModule]++; + if ((RobTypeOnModule[iModule] / 10 % 10) == 5) total_rob5[iModule]++; + if ((RobTypeOnModule[iModule] / 100) == 5) total_rob5[iModule]++; + + if ((RobTypeOnModule[iModule] % 10) == 3) total_rob3[iModule]++; + if ((RobTypeOnModule[iModule] / 10 % 10) == 3) total_rob3[iModule]++; + if ((RobTypeOnModule[iModule] / 100 % 10) == 3) total_rob3[iModule]++; + if ((RobTypeOnModule[iModule] / 1000 % 10) == 3) total_rob3[iModule]++; + if ((RobTypeOnModule[iModule] / 10000 % 10) == 3) total_rob3[iModule]++; + if ((RobTypeOnModule[iModule] / 100000 % 10) == 3) total_rob3[iModule]++; + } + + for (Int_t iModule = 0; iModule < NofModuleTypes; iModule++) { + total_rob7[iModule] *= total_modules[iModule]; + fprintf(ifile, " %8d", total_rob7[iModule]); + total_rob7[NofModuleTypes] += total_rob7[iModule]; + } + fprintf(ifile, " %8d", total_rob7[NofModuleTypes]); + fprintf(ifile, " number of GBTX ROB7\n"); + + for (Int_t iModule = 0; iModule < NofModuleTypes; iModule++) { + total_rob5[iModule] *= total_modules[iModule]; + fprintf(ifile, " %8d", total_rob5[iModule]); + total_rob5[NofModuleTypes] += total_rob5[iModule]; + } + fprintf(ifile, " %8d", total_rob5[NofModuleTypes]); + fprintf(ifile, " number of GBTX ROB5\n"); + + for (Int_t iModule = 0; iModule < NofModuleTypes; iModule++) { + total_rob3[iModule] *= total_modules[iModule]; + fprintf(ifile, " %8d", total_rob3[iModule]); + total_rob3[NofModuleTypes] += total_rob3[iModule]; + } + fprintf(ifile, " %8d", total_rob3[NofModuleTypes]); + fprintf(ifile, " number of GBTX ROB3\n"); + + //------------------------------------------------------------------------------ + fprintf(ifile, "# e-links\n"); + + // e-links used + for (Int_t iModule = 0; iModule < NofModuleTypes; iModule++) + fprintf(ifile, " %8d", asics_per_module[iModule] * 2); + fprintf(ifile, " %8d", total_asics[NofModuleTypes] * 2); + fprintf(ifile, " e-links used\n"); + + // e-links available + for (Int_t iModule = 0; iModule < NofModuleTypes; iModule++) + fprintf(ifile, " %8d", GbtxPerModule[iModule] * 14); + fprintf(ifile, " %8d", total_gbtx[NofModuleTypes] * 14); + fprintf(ifile, " e-links available\n"); + + // e-link efficiency + for (Int_t iModule = 0; iModule < NofModuleTypes; iModule++) { + if (total_gbtx[iModule] != 0) + fprintf(ifile, " %7.1f%%", (float) total_asics[iModule] * 2 / (total_gbtx[iModule] * 14) * 100); + else + fprintf(ifile, " -"); + } + if (total_gbtx[NofModuleTypes] != 0) + fprintf(ifile, " %7.1f%%", (float) total_asics[NofModuleTypes] * 2 / (total_gbtx[NofModuleTypes] * 14) * 100); + fprintf(ifile, " e-link efficiency\n\n"); + + //------------------------------------------------------------------------------ + + // number of channels + fprintf(ifile, "# channels\n"); + + // channels per module + for (Int_t iModule = 0; iModule < NofModuleTypes; iModule++) { + if ((AsicsPerFeb[iModule] % 100) == 16) { + channels_per_feb[iModule] = 80 * 6; // rows // 84, if 63 of 64 ch used + channels_per_module[iModule] = channels_per_feb[iModule] * FebsPerModule[iModule]; + } + if ((AsicsPerFeb[iModule] % 100) == 15) { + channels_per_feb[iModule] = 80 * 6; // rows + channels_per_module[iModule] = channels_per_feb[iModule] * FebsPerModule[iModule]; + } + if ((AsicsPerFeb[iModule] % 100) == 10) { + channels_per_feb[iModule] = 80 * 4; // rows + channels_per_module[iModule] = channels_per_feb[iModule] * FebsPerModule[iModule]; + } + if ((AsicsPerFeb[iModule] % 100) == 5) { + channels_per_feb[iModule] = 80 * 2; // rows + channels_per_module[iModule] = channels_per_feb[iModule] * FebsPerModule[iModule]; + } + + if ((AsicsPerFeb[iModule] % 100) == 9) { + channels_per_feb[iModule] = 144 * 2; // rows + channels_per_module[iModule] = channels_per_feb[iModule] * FebsPerModule[iModule]; + } + if ((AsicsPerFeb[iModule] % 100) == 8) { + channels_per_feb[iModule] = 128 * 2; // rows + channels_per_module[iModule] = channels_per_feb[iModule] * FebsPerModule[iModule]; + } + if ((AsicsPerFeb[iModule] % 100) == 7) { + channels_per_feb[iModule] = 112 * 2; // rows + channels_per_module[iModule] = channels_per_feb[iModule] * FebsPerModule[iModule]; + } + // Bucharest module[s] + if ((AsicsPerFeb[iModule] % 100) == 6) { + channels_per_feb[iModule] = 16 * 6; + channels_per_module[iModule] = channels_per_feb[iModule] * FebsPerModule[iModule]; + } + } + + for (Int_t iModule = 0; iModule < NofModuleTypes; iModule++) + fprintf(ifile, " %8d", channels_per_module[iModule]); + fprintf(ifile, " channels per module\n"); + + for (Int_t iModule = 0; iModule < NofModuleTypes; iModule++) + fprintf(ifile, " %8d", channels_per_feb[iModule]); + fprintf(ifile, " channels per feb\n"); + + // channels used + for (Int_t iModule = 0; iModule < NofModuleTypes; iModule++) { + total_channels[iModule] = channels_per_module[iModule] * total_modules[iModule]; + fprintf(ifile, " %8d", total_channels[iModule]); + total_channels[NofModuleTypes] += total_channels[iModule]; + } + fprintf(ifile, " %8d", total_channels[NofModuleTypes]); + fprintf(ifile, " channels used\n"); + + // channels available + fprintf(ifile, " "); + for (Int_t iModule = 0; iModule < NofModuleTypes; iModule++) { + if ((AsicsPerFeb[iModule] / 100) == 3) { + fprintf(ifile, "%8du", total_asics[iModule] * 32); + total_channels_u += total_asics[iModule] * 32; + } + else if ((AsicsPerFeb[iModule] / 100) == 2) { + fprintf(ifile, "%8ds", total_asics[iModule] * 32); + total_channels_s += total_asics[iModule] * 32; + } + else if ((AsicsPerFeb[iModule] / 100) == 1) { + fprintf(ifile, "%8d ", total_asics[iModule] * 32); + total_channels_r += total_asics[iModule] * 32; + } + else // Bucharest type + { + fprintf(ifile, "%8d ", total_asics[iModule] * 16); + total_channels_f += total_asics[iModule] * 16; + } + } + fprintf(ifile, "%8d", total_asics[NofModuleTypes] * 32); + fprintf(ifile, " channels available\n"); + + // channel ratio for u,s,r density + fprintf(ifile, " "); + fprintf(ifile, "%7.1f%%u", (float) total_channels_u / (total_asics[NofModuleTypes] * 32) * 100); + fprintf(ifile, "%7.1f%%s", (float) total_channels_s / (total_asics[NofModuleTypes] * 32) * 100); + fprintf(ifile, "%7.1f%%r", (float) total_channels_r / (total_asics[NofModuleTypes] * 32) * 100); + fprintf(ifile, "%7.1f%%f", (float) total_channels_f / (total_asics[8] * 16) * 100); + fprintf(ifile, " channel ratio\n"); + fprintf(ifile, "\n"); + fprintf(ifile, "%8.1f%% channel efficiency\n", + 1. * total_channels[NofModuleTypes] / (total_asics[NofModuleTypes] * 32) * 100); + + //------------------------------------------------------------------------------ + + // total surface of TRD + for (Int_t iModule = 0; iModule < NofModuleTypes; iModule++) + if (iModule <= 3) { + total_surface += total_modules[iModule] * DetectorSizeX[0] / 100 * DetectorSizeY[0] / 100; + total_actarea += total_modules[iModule] * (DetectorSizeX[0] - 2 * FrameWidth[0]) / 100 + * (DetectorSizeY[0] - 2 * FrameWidth[0]) / 100; + } + else { + total_surface += total_modules[iModule] * DetectorSizeX[1] / 100 * DetectorSizeY[1] / 100; + total_actarea += total_modules[iModule] * (DetectorSizeX[1] - 2 * FrameWidth[1]) / 100 + * (DetectorSizeY[1] - 2 * FrameWidth[1]) / 100; + } + fprintf(ifile, "\n"); + + // summary + fprintf(ifile, "%7.2f m2 total surface \n", total_surface); + fprintf(ifile, "%7.2f m2 total active area\n", total_actarea); + fprintf(ifile, "%7.2f m3 total gas volume \n", + total_actarea * gas_thickness / 100); // convert cm to m for thickness + + fprintf(ifile, "%7.2f cm2/ch average channel size\n", 100. * 100 * total_actarea / total_channels[NofModuleTypes]); + fprintf(ifile, "%7.2f ch/m2 channels per m2 active area\n", 1. * total_channels[NofModuleTypes] / total_actarea); + fprintf(ifile, "\n"); + + // gas volume position + fprintf(ifile, "# gas volume position\n"); + for (Int_t iLayer = 0; iLayer < MaxLayers; iLayer++) + if (ShowLayer[iLayer]) + fprintf(ifile, "%10.4f cm position of gas volume - layer %2d\n", + LayerPosition[iLayer] + LayerThickness / 2. + gas_position, PlaneId[iLayer]); + fprintf(ifile, "\n"); + + fclose(ifile); +} + + +void create_materials_from_media_file() +{ + // Use the FairRoot geometry interface to load the media which are already defined + FairGeoLoader* geoLoad = new FairGeoLoader("TGeo", "FairGeoLoader"); + FairGeoInterface* geoFace = geoLoad->getGeoInterface(); + TString geoPath = gSystem->Getenv("VMCWORKDIR"); + TString medFile = geoPath + "/geometry/media.geo"; + geoFace->setMediaFile(medFile); + geoFace->readMedia(); + + // Read the required media and create them in the GeoManager + FairGeoMedia* geoMedia = geoFace->getMedia(); + FairGeoBuilder* geoBuild = geoLoad->getGeoBuilder(); + + FairGeoMedium* air = geoMedia->getMedium(KeepingVolumeMedium); + FairGeoMedium* pefoam20 = geoMedia->getMedium(RadiatorVolumeMedium); + FairGeoMedium* G10 = geoMedia->getMedium(LatticeVolumeMedium); + FairGeoMedium* kapton = geoMedia->getMedium(KaptonVolumeMedium); + FairGeoMedium* trdGas = geoMedia->getMedium(GasVolumeMedium); + FairGeoMedium* copper = geoMedia->getMedium(PadCopperVolumeMedium); + FairGeoMedium* carbon = geoMedia->getMedium(CarbonVolumeMedium); + FairGeoMedium* honeycomb = geoMedia->getMedium(HoneycombVolumeMedium); + FairGeoMedium* aluminium = geoMedia->getMedium(AluminiumVolumeMedium); + + // FairGeoMedium* goldCoatedCopper = geoMedia->getMedium("goldcoatedcopper"); + // FairGeoMedium* polypropylene = geoMedia->getMedium("polypropylene"); + // FairGeoMedium* mylar = geoMedia->getMedium("mylar"); + + geoBuild->createMedium(air); + geoBuild->createMedium(pefoam20); + geoBuild->createMedium(trdGas); + geoBuild->createMedium(honeycomb); + geoBuild->createMedium(carbon); + geoBuild->createMedium(G10); + geoBuild->createMedium(copper); + geoBuild->createMedium(kapton); + geoBuild->createMedium(aluminium); + + // geoBuild->createMedium(goldCoatedCopper); + // geoBuild->createMedium(polypropylene); + // geoBuild->createMedium(mylar); +} + +TGeoVolume* create_trd_module_type(Int_t moduleType) +{ + Int_t type = ModuleType[moduleType - 1]; + Double_t sizeX = DetectorSizeX[type]; + Double_t sizeY = DetectorSizeY[type]; + Double_t frameWidth = FrameWidth[type]; + Double_t activeAreaX = sizeX - 2 * frameWidth; + Double_t activeAreaY = sizeY - 2 * frameWidth; + + TGeoMedium* keepVolMed = gGeoMan->GetMedium(KeepingVolumeMedium); + TGeoMedium* radVolMed = gGeoMan->GetMedium(RadiatorVolumeMedium); + TGeoMedium* latticeVolMed = gGeoMan->GetMedium(LatticeVolumeMedium); + TGeoMedium* kaptonVolMed = gGeoMan->GetMedium(KaptonVolumeMedium); + TGeoMedium* gasVolMed = gGeoMan->GetMedium(GasVolumeMedium); + TGeoMedium* padcopperVolMed = gGeoMan->GetMedium(PadCopperVolumeMedium); + TGeoMedium* padpcbVolMed = gGeoMan->GetMedium(PadPcbVolumeMedium); + TGeoMedium* honeycombVolMed = gGeoMan->GetMedium(HoneycombVolumeMedium); + TGeoMedium* carbonVolMed = gGeoMan->GetMedium(CarbonVolumeMedium); + // TGeoMedium* mylarVolMed = gGeoMan->GetMedium(MylarVolumeMedium); + // TGeoMedium* electronicsVolMed = gGeoMan->GetMedium(ElectronicsVolumeMedium); + TGeoMedium* frameVolMed = gGeoMan->GetMedium(FrameVolumeMedium); + TGeoMedium* aluledgeVolMed = gGeoMan->GetMedium(AluLegdeVolumeMedium); + TGeoMedium* febVolMed = gGeoMan->GetMedium(FebVolumeMedium); + TGeoMedium* asicVolMed = gGeoMan->GetMedium(AsicVolumeMedium); + // TGeoMedium* aluminiumVolMed = gGeoMan->GetMedium(AluminiumVolumeMedium); + + TString name = Form("module%d", moduleType); + TGeoVolume* module = new TGeoVolumeAssembly(name); + + + if (IncludeRadiator) { + // Radiator + // TGeoBBox* trd_radiator = new TGeoBBox("", activeAreaX /2., activeAreaY /2., radiator_thickness /2.); + TGeoBBox* trd_radiator = new TGeoBBox("trd_radiator", sizeX / 2., sizeY / 2., radiator_thickness / 2.); + TGeoVolume* trdmod1_radvol = new TGeoVolume("radiator", trd_radiator, radVolMed); + // TGeoVolume* trdmod1_radvol = new TGeoVolume(Form("module%d_radiator", moduleType), trd_radiator, radVolMed); + // TGeoVolume* trdmod1_radvol = new TGeoVolume(Form("trd1mod%dradiator", moduleType), trd_radiator, radVolMed); + trdmod1_radvol->SetLineColor(kBlue); + trdmod1_radvol->SetTransparency(70); // (60); // (70); // set transparency for the TRD radiator + TGeoTranslation* trd_radiator_trans = new TGeoTranslation("", 0., 0., radiator_position); + module->AddNode(trdmod1_radvol, 1, trd_radiator_trans); + } + + // Lattice grid + if (IncludeLattice) { + + if (type == 0) // inner modules + { + // printf("lattice type %d\n", type); + // drift window - lattice grid - sprossenfenster + TGeoBBox* trd_lattice_mod0_ho = new TGeoBBox("trd_lattice_mod0_ho", sizeX / 2., lattice_o_width[type] / 2., + lattice_thickness / 2.); // horizontal outer + TGeoBBox* trd_lattice_mod0_hi = + new TGeoBBox("trd_lattice_mod0_hi", sizeX / 2. - lattice_o_width[type], lattice_i_width[type] / 2., + lattice_thickness / 2.); // horizontal inner + TGeoBBox* trd_lattice_mod0_vo = + new TGeoBBox("trd_lattice_mod0_vo", lattice_o_width[type] / 2., sizeX / 2. - lattice_o_width[type], + lattice_thickness / 2.); // vertical outer + TGeoBBox* trd_lattice_mod0_vi = new TGeoBBox("trd_lattice_mod0_vi", lattice_i_width[type] / 2., + 0.20 * activeAreaY / 2. - lattice_i_width[type] / 2., + lattice_thickness / 2.); // vertical inner + TGeoBBox* trd_lattice_mod0_vb = new TGeoBBox("trd_lattice_mod0_vb", lattice_i_width[type] / 2., + 0.20 * activeAreaY / 2. - lattice_i_width[type] / 4., + lattice_thickness / 2.); // vertical border + + TGeoVolume* trd_lattice_mod0_vol_ho = new TGeoVolume("lattice0ho", trd_lattice_mod0_ho, latticeVolMed); + TGeoVolume* trd_lattice_mod0_vol_hi = new TGeoVolume("lattice0hi", trd_lattice_mod0_hi, latticeVolMed); + TGeoVolume* trd_lattice_mod0_vol_vo = new TGeoVolume("lattice0vo", trd_lattice_mod0_vo, latticeVolMed); + TGeoVolume* trd_lattice_mod0_vol_vi = new TGeoVolume("lattice0vi", trd_lattice_mod0_vi, latticeVolMed); + TGeoVolume* trd_lattice_mod0_vol_vb = new TGeoVolume("lattice0vb", trd_lattice_mod0_vb, latticeVolMed); + + trd_lattice_mod0_vol_ho->SetLineColor(kYellow); // kBlue); + trd_lattice_mod0_vol_vo->SetLineColor(kYellow); // kOrange); + trd_lattice_mod0_vol_hi->SetLineColor(kYellow); // kRed); + trd_lattice_mod0_vol_vi->SetLineColor(kYellow); // kWhite); + trd_lattice_mod0_vol_vb->SetLineColor(kYellow); + + TGeoTranslation* tv010 = + new TGeoTranslation("tv010", 0., (1.00 * activeAreaY / 2. + lattice_o_width[type] / 2.), 0); + TGeoTranslation* tv015 = + new TGeoTranslation("tv015", 0., -(1.00 * activeAreaY / 2. + lattice_o_width[type] / 2.), 0); + + TGeoTranslation* th020 = + new TGeoTranslation("th020", (1.00 * activeAreaX / 2. + lattice_o_width[type] / 2.), 0., 0); + TGeoTranslation* th025 = + new TGeoTranslation("th025", -(1.00 * activeAreaX / 2. + lattice_o_width[type] / 2.), 0., 0); + + Double_t hypos0[4] = {(0.60 * activeAreaY / 2.), (0.20 * activeAreaY / 2.), -(0.20 * activeAreaY / 2.), + -(0.60 * activeAreaY / 2.)}; + + Double_t vxpos0[4] = {(0.60 * activeAreaX / 2.), (0.20 * activeAreaX / 2.), -(0.20 * activeAreaX / 2.), + -(0.60 * activeAreaX / 2.)}; + + Double_t vypos0[5] = {(0.80 * activeAreaY / 2. + lattice_i_width[type] / 4.), (0.40 * activeAreaY / 2.), + (0.00 * activeAreaY / 2.), -(0.40 * activeAreaY / 2.), + -(0.80 * activeAreaY / 2. + lattice_i_width[type] / 4.)}; + + // TGeoVolumeAssembly* trdmod0_lattice = new TGeoVolumeAssembly("mod0lattice"); // volume for lattice grid + + TGeoBBox* trd_lattice_mod0 = new TGeoBBox("trd_lattice_mod0", sizeX / 2., sizeY / 2., lattice_thickness / 2.); + TGeoVolume* trdmod0_lattice = new TGeoVolume("lat_grid_mod0", trd_lattice_mod0, keepVolMed); + + // trdmod0_lattice->SetLineColor(kGreen); // set color for keeping volume + + // outer frame + trdmod0_lattice->AddNode(trd_lattice_mod0_vol_ho, 1, tv010); + trdmod0_lattice->AddNode(trd_lattice_mod0_vol_ho, 2, tv015); + + trdmod0_lattice->AddNode(trd_lattice_mod0_vol_vo, 3, th020); + trdmod0_lattice->AddNode(trd_lattice_mod0_vol_vo, 4, th025); + + // lattice piece number + Int_t lat0_no = 5; + + // horizontal bars + for (Int_t y = 0; y < 4; y++) { + TGeoTranslation* t0xy = new TGeoTranslation("", 0, hypos0[y], 0); + trdmod0_lattice->AddNode(trd_lattice_mod0_vol_hi, lat0_no, t0xy); + lat0_no++; + } + + // vertical bars + for (Int_t x = 0; x < 4; x++) + for (Int_t y = 0; y < 5; y++) { + TGeoTranslation* t0xy = new TGeoTranslation("", vxpos0[x], vypos0[y], 0); + if ((y == 0) || (y == 4)) trdmod0_lattice->AddNode(trd_lattice_mod0_vol_vb, lat0_no, t0xy); // border piece + else + trdmod0_lattice->AddNode(trd_lattice_mod0_vol_vi, lat0_no, t0xy); // middle piece + lat0_no++; + } + + // add lattice to module + TGeoTranslation* trd_lattice_trans = new TGeoTranslation("", 0., 0., lattice_position); + module->AddNode(trdmod0_lattice, 1, trd_lattice_trans); + } + + else if (type == 1) // outer modules + { + // printf("lattice type %d\n", type); + // drift window - lattice grid - sprossenfenster + TGeoBBox* trd_lattice_mod1_ho = new TGeoBBox("trd_lattice_mod1_ho", sizeX / 2., lattice_o_width[type] / 2., + lattice_thickness / 2.); // horizontal outer + TGeoBBox* trd_lattice_mod1_hi = + new TGeoBBox("trd_lattice_mod1_hi", sizeX / 2. - lattice_o_width[type], lattice_i_width[type] / 2., + lattice_thickness / 2.); // horizontal inner + TGeoBBox* trd_lattice_mod1_vo = + new TGeoBBox("trd_lattice_mod1_vo", lattice_o_width[type] / 2., sizeX / 2. - lattice_o_width[type], + lattice_thickness / 2.); // vertical outer + TGeoBBox* trd_lattice_mod1_vi = new TGeoBBox("trd_lattice_mod1_vi", lattice_i_width[type] / 2., + 0.125 * activeAreaY / 2. - lattice_i_width[type] / 2., + lattice_thickness / 2.); // vertical inner + TGeoBBox* trd_lattice_mod1_vb = new TGeoBBox("trd_lattice_mod1_vb", lattice_i_width[type] / 2., + 0.125 * activeAreaY / 2. - lattice_i_width[type] / 4., + lattice_thickness / 2.); // vertical border + + TGeoVolume* trd_lattice_mod1_vol_ho = new TGeoVolume("lattice1ho", trd_lattice_mod1_ho, latticeVolMed); + TGeoVolume* trd_lattice_mod1_vol_hi = new TGeoVolume("lattice1hi", trd_lattice_mod1_hi, latticeVolMed); + TGeoVolume* trd_lattice_mod1_vol_vo = new TGeoVolume("lattice1vo", trd_lattice_mod1_vo, latticeVolMed); + TGeoVolume* trd_lattice_mod1_vol_vi = new TGeoVolume("lattice1vi", trd_lattice_mod1_vi, latticeVolMed); + TGeoVolume* trd_lattice_mod1_vol_vb = new TGeoVolume("lattice1vb", trd_lattice_mod1_vb, latticeVolMed); + + trd_lattice_mod1_vol_ho->SetLineColor(kYellow); // kBlue); + trd_lattice_mod1_vol_vo->SetLineColor(kYellow); // kOrange); + trd_lattice_mod1_vol_hi->SetLineColor(kYellow); // kRed); + trd_lattice_mod1_vol_vi->SetLineColor(kYellow); // kWhite); + trd_lattice_mod1_vol_vb->SetLineColor(kYellow); + + TGeoTranslation* tv110 = + new TGeoTranslation("tv110", 0., (1.00 * activeAreaY / 2. + lattice_o_width[type] / 2.), 0); + TGeoTranslation* tv118 = + new TGeoTranslation("tv118", 0., -(1.00 * activeAreaY / 2. + lattice_o_width[type] / 2.), 0); + + TGeoTranslation* th120 = + new TGeoTranslation("th120", (1.00 * activeAreaX / 2. + lattice_o_width[type] / 2.), 0., 0); + TGeoTranslation* th128 = + new TGeoTranslation("th128", -(1.00 * activeAreaX / 2. + lattice_o_width[type] / 2.), 0., 0); + + Double_t hypos1[7] = {(0.75 * activeAreaY / 2.), (0.50 * activeAreaY / 2.), (0.25 * activeAreaY / 2.), + (0.00 * activeAreaY / 2.), -(0.25 * activeAreaY / 2.), -(0.50 * activeAreaY / 2.), + -(0.75 * activeAreaY / 2.)}; + + Double_t vxpos1[7] = {(0.75 * activeAreaX / 2.), (0.50 * activeAreaX / 2.), (0.25 * activeAreaX / 2.), + (0.00 * activeAreaX / 2.), -(0.25 * activeAreaX / 2.), -(0.50 * activeAreaX / 2.), + -(0.75 * activeAreaX / 2.)}; + + Double_t vypos1[8] = {(0.875 * activeAreaY / 2. + lattice_i_width[type] / 4.), + (0.625 * activeAreaY / 2.), + (0.375 * activeAreaY / 2.), + (0.125 * activeAreaY / 2.), + -(0.125 * activeAreaY / 2.), + -(0.375 * activeAreaY / 2.), + -(0.625 * activeAreaY / 2.), + -(0.875 * activeAreaY / 2. + lattice_i_width[type] / 4.)}; + + // TGeoVolumeAssembly* trdmod1_lattice = new TGeoVolumeAssembly("mod1lattice"); // volume for lattice grid + + TGeoBBox* trd_lattice_mod1 = new TGeoBBox("trd_lattice_mod1", sizeX / 2., sizeY / 2., lattice_thickness / 2.); + TGeoVolume* trdmod1_lattice = new TGeoVolume("lat_grid_mod1", trd_lattice_mod1, keepVolMed); + + // trdmod1_lattice->SetLineColor(kGreen); // set color for keeping volume + + // outer frame + trdmod1_lattice->AddNode(trd_lattice_mod1_vol_ho, 1, tv110); + trdmod1_lattice->AddNode(trd_lattice_mod1_vol_ho, 2, tv118); + + trdmod1_lattice->AddNode(trd_lattice_mod1_vol_vo, 3, th120); + trdmod1_lattice->AddNode(trd_lattice_mod1_vol_vo, 4, th128); + + // lattice piece number + Int_t lat1_no = 5; + + // horizontal bars + for (Int_t y = 0; y < 7; y++) { + TGeoTranslation* t1xy = new TGeoTranslation("", 0, hypos1[y], 0); + trdmod1_lattice->AddNode(trd_lattice_mod1_vol_hi, lat1_no, t1xy); + lat1_no++; + } + + // vertical bars + for (Int_t x = 0; x < 7; x++) + for (Int_t y = 0; y < 8; y++) { + TGeoTranslation* t1xy = new TGeoTranslation("", vxpos1[x], vypos1[y], 0); + if ((y == 0) || (y == 7)) trdmod1_lattice->AddNode(trd_lattice_mod1_vol_vb, lat1_no, t1xy); // border piece + else + trdmod1_lattice->AddNode(trd_lattice_mod1_vol_vi, lat1_no, t1xy); // middle piece + lat1_no++; + } + + // add lattice to module + TGeoTranslation* trd_lattice_trans = new TGeoTranslation("", 0., 0., lattice_position); + module->AddNode(trdmod1_lattice, 1, trd_lattice_trans); + } + + } // with lattice grid + + if (IncludeKaptonFoil) { + // Kapton Foil + TGeoBBox* trd_kapton = new TGeoBBox("trd_kapton", sizeX / 2., sizeY / 2., kapton_thickness / 2.); + TGeoVolume* trdmod1_kaptonvol = new TGeoVolume("kaptonfoil", trd_kapton, kaptonVolMed); + // TGeoVolume* trdmod1_kaptonvol = new TGeoVolume(Form("module%d_kaptonfoil", moduleType), trd_kapton, kaptonVolMed); + // TGeoVolume* trdmod1_kaptonvol = new TGeoVolume(Form("trd1mod%dkapton", moduleType), trd_kapton, kaptonVolMed); + trdmod1_kaptonvol->SetLineColor(kGreen); + TGeoTranslation* trd_kapton_trans = new TGeoTranslation("", 0., 0., kapton_position); + module->AddNode(trdmod1_kaptonvol, 1, trd_kapton_trans); + } + + // start of Frame in z + // Gas + TGeoBBox* trd_gas = new TGeoBBox("trd_gas", activeAreaX / 2., activeAreaY / 2., gas_thickness / 2.); + TGeoVolume* trdmod1_gasvol = new TGeoVolume("gas", trd_gas, gasVolMed); + // TGeoVolume* trdmod1_gasvol = new TGeoVolume(Form("module%d_gas", moduleType), trd_gas, gasVolMed); + // TGeoVolume* trdmod1_gasvol = new TGeoVolume(Form("trd1mod%dgas", moduleType), trd_gas, gasVolMed); + // trdmod1_gasvol->SetLineColor(kBlue); + trdmod1_gasvol->SetLineColor(kGreen); // to avoid blue overlaps in the screenshots + trdmod1_gasvol->SetTransparency(40); // set transparency for the TRD gas + TGeoTranslation* trd_gas_trans = new TGeoTranslation("", 0., 0., gas_position); + module->AddNode(trdmod1_gasvol, 1, trd_gas_trans); + // end of Frame in z + + if (IncludeGasFrame) { + // frame1 + TGeoBBox* trd_frame1 = new TGeoBBox("trd_frame1", sizeX / 2., frameWidth / 2., frame_thickness / 2.); + TGeoVolume* trdmod1_frame1vol = new TGeoVolume("frame1", trd_frame1, frameVolMed); + trdmod1_frame1vol->SetLineColor(kRed); + + // translations + TGeoTranslation* trd_frame1_trans = new TGeoTranslation("", 0., activeAreaY / 2. + frameWidth / 2., frame_position); + module->AddNode(trdmod1_frame1vol, 1, trd_frame1_trans); + trd_frame1_trans = new TGeoTranslation("", 0., -(activeAreaY / 2. + frameWidth / 2.), frame_position); + module->AddNode(trdmod1_frame1vol, 2, trd_frame1_trans); + + + // frame2 + TGeoBBox* trd_frame2 = new TGeoBBox("trd_frame2", frameWidth / 2., activeAreaY / 2., frame_thickness / 2.); + TGeoVolume* trdmod1_frame2vol = new TGeoVolume("frame2", trd_frame2, frameVolMed); + trdmod1_frame2vol->SetLineColor(kRed); + + // translations + TGeoTranslation* trd_frame2_trans = new TGeoTranslation("", activeAreaX / 2. + frameWidth / 2., 0., frame_position); + module->AddNode(trdmod1_frame2vol, 1, trd_frame2_trans); + trd_frame2_trans = new TGeoTranslation("", -(activeAreaX / 2. + frameWidth / 2.), 0., frame_position); + module->AddNode(trdmod1_frame2vol, 2, trd_frame2_trans); + } + + if (IncludePadplane) { + // Pad Copper + TGeoBBox* trd_padcopper = new TGeoBBox("trd_padcopper", sizeX / 2., sizeY / 2., padcopper_thickness / 2.); + TGeoVolume* trdmod1_padcoppervol = new TGeoVolume("padcopper", trd_padcopper, padcopperVolMed); + // TGeoVolume* trdmod1_padcoppervol = new TGeoVolume(Form("module%d_padcopper", moduleType), trd_padcopper, padcopperVolMed); + // TGeoVolume* trdmod1_padcoppervol = new TGeoVolume(Form("trd1mod%dpadcopper", moduleType), trd_padcopper, padcopperVolMed); + trdmod1_padcoppervol->SetLineColor(kOrange); + TGeoTranslation* trd_padcopper_trans = new TGeoTranslation("", 0., 0., padcopper_position); + module->AddNode(trdmod1_padcoppervol, 1, trd_padcopper_trans); + + // Pad Plane + TGeoBBox* trd_padpcb = new TGeoBBox("trd_padpcb", sizeX / 2., sizeY / 2., padplane_thickness / 2.); + TGeoVolume* trdmod1_padpcbvol = new TGeoVolume("padplane", trd_padpcb, padpcbVolMed); + // TGeoVolume* trdmod1_padpcbvol = new TGeoVolume(Form("module%d_padplane", moduleType), trd_padpcb, padpcbVolMed); + // TGeoVolume* trdmod1_padpcbvol = new TGeoVolume(Form("trd1mod%dpadplane", moduleType), trd_padpcb, padpcbVolMed); + trdmod1_padpcbvol->SetLineColor(kBlue); + TGeoTranslation* trd_padpcb_trans = new TGeoTranslation("", 0., 0., padplane_position); + module->AddNode(trdmod1_padpcbvol, 1, trd_padpcb_trans); + } + + if (IncludeBackpanel) { + // Honeycomb + TGeoBBox* trd_honeycomb = new TGeoBBox("trd_honeycomb", sizeX / 2., sizeY / 2., honeycomb_thickness / 2.); + TGeoVolume* trdmod1_honeycombvol = new TGeoVolume("honeycomb", trd_honeycomb, honeycombVolMed); + // TGeoVolume* trdmod1_honeycombvol = new TGeoVolume(Form("module%d_honeycomb", moduleType), trd_honeycomb, honeycombVolMed); + // TGeoVolume* trdmod1_honeycombvol = new TGeoVolume(Form("trd1mod%dhoneycomb", moduleType), trd_honeycomb, honeycombVolMed); + trdmod1_honeycombvol->SetLineColor(kOrange); + TGeoTranslation* trd_honeycomb_trans = new TGeoTranslation("", 0., 0., honeycomb_position); + module->AddNode(trdmod1_honeycombvol, 1, trd_honeycomb_trans); + + // Carbon fiber layers + TGeoBBox* trd_carbon = new TGeoBBox("trd_carbon", sizeX / 2., sizeY / 2., carbon_thickness / 2.); + TGeoVolume* trdmod1_carbonvol = new TGeoVolume("carbonsheet", trd_carbon, carbonVolMed); + // TGeoVolume* trdmod1_carbonvol = new TGeoVolume(Form("module%d_carbonsheet", moduleType), trd_carbon, carbonVolMed); + // TGeoVolume* trdmod1_carbonvol = new TGeoVolume(Form("trd1mod%dcarbon", moduleType), trd_carbon, carbonVolMed); + trdmod1_carbonvol->SetLineColor(kGreen); + TGeoTranslation* trd_carbon_trans = new TGeoTranslation("", 0., 0., carbon_position); + module->AddNode(trdmod1_carbonvol, 1, trd_carbon_trans); + } + + if (IncludeAluLedge) { + // Al-ledge + TGeoBBox* trd_aluledge1 = new TGeoBBox("trd_aluledge1", sizeY / 2., aluminium_width / 2., aluminium_thickness / 2.); + TGeoVolume* trdmod1_aluledge1vol = new TGeoVolume("aluledge1", trd_aluledge1, aluledgeVolMed); + trdmod1_aluledge1vol->SetLineColor(kRed); + + // translations + TGeoTranslation* trd_aluledge1_trans = + new TGeoTranslation("", 0., sizeY / 2. - aluminium_width / 2., aluminium_position); + module->AddNode(trdmod1_aluledge1vol, 1, trd_aluledge1_trans); + trd_aluledge1_trans = new TGeoTranslation("", 0., -(sizeY / 2. - aluminium_width / 2.), aluminium_position); + module->AddNode(trdmod1_aluledge1vol, 2, trd_aluledge1_trans); + + + // Al-ledge + TGeoBBox* trd_aluledge2 = + new TGeoBBox("trd_aluledge2", aluminium_width / 2., sizeY / 2. - aluminium_width, aluminium_thickness / 2.); + TGeoVolume* trdmod1_aluledge2vol = new TGeoVolume("aluledge2", trd_aluledge2, aluledgeVolMed); + trdmod1_aluledge2vol->SetLineColor(kRed); + + // translations + TGeoTranslation* trd_aluledge2_trans = + new TGeoTranslation("", sizeX / 2. - aluminium_width / 2., 0., aluminium_position); + module->AddNode(trdmod1_aluledge2vol, 1, trd_aluledge2_trans); + trd_aluledge2_trans = new TGeoTranslation("", -(sizeX / 2. - aluminium_width / 2.), 0., aluminium_position); + module->AddNode(trdmod1_aluledge2vol, 2, trd_aluledge2_trans); + } + + // FEBs + if (IncludeFebs) { + // assemblies + TGeoVolumeAssembly* trd_feb_vol = new TGeoVolumeAssembly("febvol"); // the mother volume of all FEBs + TGeoVolumeAssembly* trd_feb_box = + new TGeoVolumeAssembly("febbox"); // volume for inclined FEBs, then shifted along y + //TGeoVolumeAssembly* trd_feb_vol = new TGeoVolumeAssembly(Form("module%d_febvol", moduleType)); // the mother volume of all FEBs + //TGeoVolumeAssembly* trd_feb_box = new TGeoVolumeAssembly(Form("module%d_febbox", moduleType)); // volume for inclined FEBs, then shifted along y + //TGeoVolumeAssembly* trd_feb_vol = new TGeoVolumeAssembly(Form("trd1mod%dfebvol", moduleType)); // the mother volume of all FEBs + //TGeoVolumeAssembly* trd_feb_box = new TGeoVolumeAssembly(Form("trd1mod%dfebbox", moduleType)); // volume for inclined FEBs, then shifted along y + + // translations + rotations + TGeoTranslation* trd_feb_trans1; // center to corner + TGeoTranslation* trd_feb_trans2; // corner back + TGeoRotation* trd_feb_rotation; // rotation around x axis + TGeoTranslation* trd_feb_y_position; // shift to y position on TRD + // TGeoTranslation *trd_feb_null; // no displacement + + // replaced by matrix operation (see below) + // // Double_t yback, zback; + // // TGeoCombiTrans *trd_feb_placement; + // // // fix Z back offset 0.3 at some point + // // yback = - sin(feb_rotation_angle/180*3.141) * feb_width /2.; + // // zback = - (1-cos(feb_rotation_angle/180*3.141)) * feb_width /2. + 0.3; + // // trd_feb_placement = new TGeoCombiTrans(0, feb_pos_y + yback, zback, trd_feb_rotation); + // // trd_feb_box->AddNode(trdmod1_feb, iFeb+1, trd_feb_placement); + + // trd_feb_null = new TGeoTranslation("", 0., 0., 0.); // empty operation + trd_feb_trans1 = new TGeoTranslation("", 0., -feb_thickness / 2., + -feb_width / 2.); // move bottom right corner to center + trd_feb_trans2 = new TGeoTranslation("", 0., feb_thickness / 2., + feb_width / 2.); // move bottom right corner back + trd_feb_rotation = new TGeoRotation(); + trd_feb_rotation->RotateX(feb_rotation_angle[moduleType - 1]); + + TGeoHMatrix* incline_feb = new TGeoHMatrix(""); + + // (*incline_feb) = (*trd_feb_null); // OK + // (*incline_feb) = (*trd_feb_y_position); // OK + // (*incline_feb) = (*trd_feb_trans1); // OK + // (*incline_feb) = (*trd_feb_trans1) * (*trd_feb_y_position); // OK + // (*incline_feb) = (*trd_feb_trans1) * (*trd_feb_trans2); // OK + // (*incline_feb) = (*trd_feb_trans1) * (*trd_feb_rotation); // OK + // (*incline_feb) = (*trd_feb_trans1) * (*trd_feb_rotation) * (*trd_feb_trans2) * (*trd_feb_y_position); // not OK + // trd_feb_y_position is displaced in rotated coordinate system + + // matrix operation to rotate FEB PCB around its corner on the backanel + (*incline_feb) = (*trd_feb_trans1) * (*trd_feb_rotation) * (*trd_feb_trans2); // OK + + // Create all FEBs and place them in an assembly which will be added to the TRD module + TGeoBBox* trd_feb = new TGeoBBox("trd_feb", activeAreaX / 2., feb_thickness / 2., + feb_width / 2.); // the FEB itself - as a cuboid + TGeoVolume* trdmod1_feb = new TGeoVolume("feb", trd_feb, febVolMed); // the FEB made of a certain medium + // TGeoVolume* trdmod1_feb = new TGeoVolume(Form("module%d_feb", moduleType), trd_feb, febVolMed); // the FEB made of a certain medium + // TGeoVolume* trdmod1_feb = new TGeoVolume(Form("trd1mod%dfeb", moduleType), trd_feb, febVolMed); // the FEB made of a certain medium + trdmod1_feb->SetLineColor(kYellow); // set yellow color + trd_feb_box->AddNode(trdmod1_feb, 1, incline_feb); + // now we have an inclined FEB + + // ASICs + if (IncludeAsics) { + Double_t asic_pos; + Double_t asic_pos_x; + TGeoTranslation* trd_asic_trans0; // ASIC on FEB x position + TGeoTranslation* trd_asic_trans1; // center to corner + TGeoTranslation* trd_asic_trans2; // corner back + TGeoRotation* trd_asic_rotation; // rotation around x axis + + trd_asic_trans1 = new TGeoTranslation("", 0., -(feb_thickness + asic_offset + asic_thickness / 2.), + -feb_width / 2.); // move ASIC center to FEB corner + trd_asic_trans2 = new TGeoTranslation("", 0., feb_thickness + asic_offset + asic_thickness / 2., + feb_width / 2.); // move FEB corner back to asic center + trd_asic_rotation = new TGeoRotation(); + trd_asic_rotation->RotateX(feb_rotation_angle[moduleType - 1]); + + TGeoHMatrix* incline_asic; + + // put many ASICs on each inclined FEB + TGeoBBox* trd_asic = new TGeoBBox("trd_asic", asic_width / 2., asic_thickness / 2., + asic_width / 2.); // ASIC dimensions + // TODO: use Silicon as ASICs material + TGeoVolume* trdmod1_asic = new TGeoVolume("asic", trd_asic, asicVolMed); // the ASIC made of a certain medium + // TGeoVolume* trdmod1_asic = new TGeoVolume(Form("module%d_asic", moduleType), trd_asic, asicVolMed); // the ASIC made of a certain medium + // TGeoVolume* trdmod1_asic = new TGeoVolume(Form("trd1mod%dasic", moduleType), trd_asic, asicVolMed); // the ASIC made of a certain medium + trdmod1_asic->SetLineColor(kBlue); // set blue color for ASICs + + Int_t nofAsics = AsicsPerFeb[moduleType - 1] % 100; + Int_t groupAsics = AsicsPerFeb[moduleType - 1] / 100; // either 1 or 2 or 3 (new ultimate) + + if ((nofAsics == 16) && (activeAreaX < 60)) asic_distance = 0.0; // for 57 cm // 0.1; // for 60 cm + else + asic_distance = 0.4; + + for (Int_t iAsic = 0; iAsic < (nofAsics / groupAsics); iAsic++) { + if (groupAsics == 1) // single ASICs + { + asic_pos = + (iAsic + 0.5) / nofAsics - 0.5; // equal spacing of ASICs on the FEB, e.g. for no=3 : -1/3, 0, +1/3 + + // ASIC 1 + asic_pos_x = asic_pos * activeAreaX; + trd_asic_trans0 = new TGeoTranslation("", asic_pos_x, feb_thickness / 2. + asic_thickness / 2. + asic_offset, + 0.); // move asic on top of FEB + incline_asic = new TGeoHMatrix(""); + (*incline_asic) = (*trd_asic_trans0) * (*trd_asic_trans1) * (*trd_asic_rotation) * (*trd_asic_trans2); // OK + trd_feb_box->AddNode(trdmod1_asic, iAsic + 1, + incline_asic); // now we have ASICs on the inclined FEB + } + + if (groupAsics == 2) // pairs of ASICs + { + asic_pos = (iAsic + 0.5) / (nofAsics / groupAsics) + - 0.5; // equal spacing of ASICs on the FEB, e.g. for no=3 : -1/3, 0, +1/3 + + // ASIC 1 + asic_pos_x = asic_pos * activeAreaX + (0.5 + asic_distance / 2.) * asic_width; + trd_asic_trans0 = new TGeoTranslation("", asic_pos_x, feb_thickness / 2. + asic_thickness / 2. + asic_offset, + 0.); // move asic on top of FEB); + incline_asic = new TGeoHMatrix(""); + (*incline_asic) = (*trd_asic_trans0) * (*trd_asic_trans1) * (*trd_asic_rotation) * (*trd_asic_trans2); // OK + trd_feb_box->AddNode(trdmod1_asic, 2 * iAsic + 1, + incline_asic); // now we have ASICs on the inclined FEB + + // ASIC 2 + asic_pos_x = asic_pos * activeAreaX - (0.5 + asic_distance / 2.) * asic_width; + trd_asic_trans0 = new TGeoTranslation("", asic_pos_x, feb_thickness / 2. + asic_thickness / 2. + asic_offset, + 0.); // move asic on top of FEB + incline_asic = new TGeoHMatrix(""); + (*incline_asic) = (*trd_asic_trans0) * (*trd_asic_trans1) * (*trd_asic_rotation) * (*trd_asic_trans2); // OK + trd_feb_box->AddNode(trdmod1_asic, 2 * iAsic + 2, + incline_asic); // now we have ASICs on the inclined FEB + } + + if (groupAsics == 3) // triplets of ASICs + { + asic_pos = (iAsic + 0.5) / (nofAsics / groupAsics) + - 0.5; // equal spacing of ASICs on the FEB, e.g. for no=3 : -1/3, 0, +1/3 + + // ASIC 1 + asic_pos_x = asic_pos * activeAreaX + 1.1 * asic_width; // (0.5 + asic_distance/2.) * asic_width; + trd_asic_trans0 = new TGeoTranslation("", asic_pos_x, feb_thickness / 2. + asic_thickness / 2. + asic_offset, + 0.); // move asic on top of FEB); + incline_asic = new TGeoHMatrix(""); + (*incline_asic) = (*trd_asic_trans0) * (*trd_asic_trans1) * (*trd_asic_rotation) * (*trd_asic_trans2); // OK + trd_feb_box->AddNode(trdmod1_asic, 3 * iAsic + 1, + incline_asic); // now we have ASICs on the inclined FEB + + // ASIC 2 + asic_pos_x = asic_pos * activeAreaX; + trd_asic_trans0 = new TGeoTranslation("", asic_pos_x, feb_thickness / 2. + asic_thickness / 2. + asic_offset, + 0.); // move asic on top of FEB + incline_asic = new TGeoHMatrix(""); + (*incline_asic) = (*trd_asic_trans0) * (*trd_asic_trans1) * (*trd_asic_rotation) * (*trd_asic_trans2); // OK + trd_feb_box->AddNode(trdmod1_asic, 3 * iAsic + 2, + incline_asic); // now we have ASICs on the inclined FEB + + // ASIC 3 + asic_pos_x = asic_pos * activeAreaX - 1.1 * asic_width; // (0.5 + asic_distance/2.) * asic_width; + trd_asic_trans0 = new TGeoTranslation("", asic_pos_x, feb_thickness / 2. + asic_thickness / 2. + asic_offset, + 0.); // move asic on top of FEB + incline_asic = new TGeoHMatrix(""); + (*incline_asic) = (*trd_asic_trans0) * (*trd_asic_trans1) * (*trd_asic_rotation) * (*trd_asic_trans2); // OK + trd_feb_box->AddNode(trdmod1_asic, 3 * iAsic + 3, + incline_asic); // now we have ASICs on the inclined FEB + } + } + // now we have an inclined FEB with ASICs + } + + + // now go on with FEB placement + Double_t feb_pos; + Double_t feb_pos_y; + + Int_t nofFebs = FebsPerModule[moduleType - 1]; + for (Int_t iFeb = 0; iFeb < nofFebs; iFeb++) { + feb_pos = (iFeb + 0.5) / nofFebs - 0.5; // equal spacing of FEBs on the backpanel + // cout << "feb_pos " << iFeb << ": " << feb_pos << endl; + feb_pos_y = feb_pos * activeAreaY; + feb_pos_y += feb_width / 2. * sin(feb_rotation_angle[moduleType - 1] * acos(-1.) / 180.); + + // shift inclined FEB in y to its final position + trd_feb_y_position = new TGeoTranslation("", 0., feb_pos_y, + feb_z_offset); // with additional fixed offset in z direction + // trd_feb_y_position = new TGeoTranslation("", 0., feb_pos_y, 0.0); // touching the backpanel with the corner + trd_feb_vol->AddNode(trd_feb_box, iFeb + 1, trd_feb_y_position); // position FEB in y + } + + if (IncludeRobs) { + // GBTx ROBs + Double_t rob_size_x = 20.0; // 13.0; // 130 mm + Double_t rob_size_y = 9.0; // 4.5; // 45 mm + Double_t rob_offset = 1.2; + Double_t rob_thickness = feb_thickness; + + TGeoVolumeAssembly* trd_rob_box = + new TGeoVolumeAssembly("robbox"); // volume for inclined FEBs, then shifted along y + TGeoBBox* trd_rob = new TGeoBBox("trd_rob", rob_size_x / 2., rob_size_y / 2., + rob_thickness / 2.); // the ROB itself + TGeoVolume* trdmod1_rob = new TGeoVolume("rob", trd_rob, febVolMed); // the ROB made of a certain medium + trdmod1_rob->SetLineColor(kRed); // set color + + // TGeoHMatrix *incline_rob = new TGeoHMatrix(""); + trd_rob_box->AddNode(trdmod1_rob, 1); + + // GBTXs + Double_t gbtx_pos; + Double_t gbtx_pos_x; + Double_t gbtx_pos_y; + TGeoTranslation* trd_gbtx_trans1; // center to corner + + // GBTX parameters + const Double_t gbtx_thickness = 0.25; // 2.5 mm + const Double_t gbtx_width = 3.0; // 2.0; 1.0; // 1 cm + + // put many GBTXs on each inclined FEB + TGeoBBox* trd_gbtx = new TGeoBBox("trd_gbtx", gbtx_width / 2., gbtx_width / 2., + gbtx_thickness / 2.); // GBTX dimensions + TGeoVolume* trdmod1_gbtx = new TGeoVolume("gbtx", trd_gbtx, asicVolMed); // the GBTX made of a certain medium + trdmod1_gbtx->SetLineColor(kGreen); // set color for GBTXs + + Int_t nofGbtxs = GbtxPerRob[moduleType - 1] % 100; + Int_t groupGbtxs = GbtxPerRob[moduleType - 1] / 100; // usually 1 + + // nofGbtxs = 7; + // groupGbtxs = 1; + + Int_t nofGbtxX = (nofGbtxs - 1) / 2. + 1; // +1 is for GBTx master + Int_t nofGbtxY = 2; + + Double_t gbtx_distance = 0.4; + Int_t iGbtx = 1; + + for (Int_t iGbtxX = 0; iGbtxX < nofGbtxX; iGbtxX++) { + gbtx_pos = (iGbtxX + 0.5) / nofGbtxX - 0.5; // equal spacing of GBTXs on the FEB, e.g. for no=3 : -1/3, 0, +1/3 + gbtx_pos_x = -gbtx_pos * rob_size_x; + + if (iGbtxX > 0) + for (Int_t iGbtxY = 0; iGbtxY < nofGbtxY; iGbtxY++) { + gbtx_pos = + (iGbtxY + 0.5) / nofGbtxY - 0.5; // equal spacing of GBTXs on the FEB, e.g. for no=3 : -1/3, 0, +1/3 + gbtx_pos_y = gbtx_pos * rob_size_y; + + trd_gbtx_trans1 = new TGeoTranslation("", gbtx_pos_x, gbtx_pos_y, + rob_thickness / 2. + gbtx_thickness / 2.); // move gbtx on top of ROB + trd_rob_box->AddNode(trdmod1_gbtx, iGbtx++, + trd_gbtx_trans1); // now we have GBTXs on the ROB + } + else { + gbtx_pos_y = 0; + + trd_gbtx_trans1 = new TGeoTranslation("", gbtx_pos_x, gbtx_pos_y, + rob_thickness / 2. + gbtx_thickness / 2.); // move gbtx on top of ROB + trd_rob_box->AddNode(trdmod1_gbtx, iGbtx++, + trd_gbtx_trans1); // now we have GBTXs on the ROB + } + } + + // now go on with ROB placement + Double_t rob_pos; + Double_t rob_pos_y; + TGeoTranslation* trd_rob_y_position; // shift to y position on TRD + + Int_t nofRobs = RobsPerModule[moduleType - 1]; + for (Int_t iRob = 0; iRob < nofRobs; iRob++) { + rob_pos = (iRob + 0.5) / nofRobs - 0.5; // equal spacing of ROBs on the backpanel + rob_pos_y = rob_pos * activeAreaY; + + // shift inclined ROB in y to its final position + if (feb_rotation_angle[moduleType - 1] == 90) // if FEB parallel to backpanel + trd_rob_y_position = new TGeoTranslation("", 0., rob_pos_y, + -feb_width / 2. + rob_offset); // place ROBs close to FEBs + else { + // Int_t rob_z_pos = 0.; // test where ROB is placed by default + Int_t rob_z_pos = + -feb_width / 2. + feb_width * cos(feb_rotation_angle[moduleType - 1] * acos(-1.) / 180.) + rob_offset; + if (rob_z_pos > feb_width / 2.) // if the rob is too far out + { + rob_z_pos = feb_width / 2. - rob_thickness; // place ROBs at end of feb volume + std::cout << "GBTx ROB was outside of the FEB volume, check " + "overlap with FEB" + << std::endl; + } + trd_rob_y_position = new TGeoTranslation("", 0., rob_pos_y, rob_z_pos); + } + trd_feb_vol->AddNode(trd_rob_box, iRob + 1, trd_rob_y_position); // position FEB in y + } + + } // IncludeGbtx + + // put FEB box on module + TGeoTranslation* trd_febvolume_trans = new TGeoTranslation("", 0., 0., febvolume_position); + gGeoMan->GetVolume(name)->AddNode(trd_feb_vol, 1, + trd_febvolume_trans); // put febvolume at correct z position wrt to the module + } + + return module; +} + + +//________________________________________________________________________________________________ +// TRD Bucharest module definition +TGeoTranslation* tr(NULL); +TString sexpr; +void addFlatCableHoles(const Char_t* name) +{ + sexpr = name; + sexpr += "_bd"; + for (Int_t c(0); c < 9; c++) { + for (Int_t r(0); r < 10; r++) { + tr = new TGeoTranslation(Form("t%s%d%02d", name, c, r), (c - 4) * 6, 1.35 + 2.7 * r, 0.); + tr->RegisterYourself(); + sexpr += Form("-%s_fc:t%s%d%02d", name, name, c, r); + } + for (Int_t r(0); r < 10; r++) { + tr = new TGeoTranslation(Form("t%s%d%02d", name, c, 10 + r), (c - 4) * 6, -1.35 - 2.7 * r, 0.); + tr->RegisterYourself(); + sexpr += Form("-%s_fc:t%s%d%02d", name, name, c, 10 + r); + } + } +} +TGeoVolume* create_trdi_module_type(Int_t type) +{ + Info("create_trdi_module_type", "Bulding Bucharest Module [%d].", type); + Int_t moduleType = 8; + Double_t sizeX = DetectorSizeX[2]; + Double_t sizeY = DetectorSizeY[2]; + Double_t frameWidth = FrameWidth[2]; + Double_t activeAreaX = sizeX - 2 * frameWidth; + Double_t activeAreaY = sizeY - 2 * frameWidth; + + TGeoMedium* keepVolMed = gGeoMan->GetMedium(KeepingVolumeMedium); + TGeoMedium* radVolMed = gGeoMan->GetMedium(RadiatorVolumeMedium); + TGeoMedium* latticeVolMed = gGeoMan->GetMedium(LatticeVolumeMedium); + TGeoMedium* kaptonVolMed = gGeoMan->GetMedium(KaptonVolumeMedium); + TGeoMedium* gasVolMed = gGeoMan->GetMedium(GasVolumeMedium); + TGeoMedium* padcopperVolMed = gGeoMan->GetMedium(PadCopperVolumeMedium); + TGeoMedium* padpcbVolMed = gGeoMan->GetMedium(PadPcbVolumeMedium); + TGeoMedium* honeycombVolMed = gGeoMan->GetMedium(HoneycombVolumeMedium); + TGeoMedium* carbonVolMed = gGeoMan->GetMedium(CarbonVolumeMedium); + // TGeoMedium* mylarVolMed = gGeoMan->GetMedium(MylarVolumeMedium); + // TGeoMedium* electronicsVolMed = gGeoMan->GetMedium(ElectronicsVolumeMedium); + TGeoMedium* frameVolMed = gGeoMan->GetMedium(FrameVolumeMedium); + TGeoMedium* febVolMed = gGeoMan->GetMedium(FebVolumeMedium); + TGeoMedium* asicVolMed = gGeoMan->GetMedium(AsicVolumeMedium); + TGeoMedium* aluminiumVolMed = gGeoMan->GetMedium(AluminiumVolumeMedium); + + TString name = Form("module%d", 9 + type); + TGeoVolume* module = new TGeoVolumeAssembly(name); + + + if (IncludeRadiator) { // Radiator + TGeoBBox* trd_radiator = new TGeoBBox("trd_radiator", sizeX / 2., sizeY / 2., radiator_thickness / 2.); + TGeoVolume* trdmod1_radvol = new TGeoVolume("Radiator", trd_radiator, radVolMed); + trdmod1_radvol->SetLineColor(kRed); + trdmod1_radvol->SetTransparency(50); // set transparency for the TRD radiator + TGeoTranslation* trd_radiator_trans = new TGeoTranslation("", 0., 0., radiator_position); + module->AddNode(trdmod1_radvol, 1, trd_radiator_trans); + } + + Double_t winIn_C_thickness = 0.02; + Double_t winIn_HC_thickness = 1.; + Double_t winIn_thickness = winIn_HC_thickness + /*2**/ winIn_C_thickness; + if (IncludeLattice) { // Entrance window in the case of the Bucharest prototype + // Carbon fiber layers + TGeoBBox* winIn_C = new TGeoBBox("winIn_C", 0.3 + activeAreaX / 2., 0.9 + activeAreaY / 2., winIn_C_thickness / 2.); + TGeoVolume* vol_winIn_C = new TGeoVolume("vol_winIn_C", winIn_C, carbonVolMed); + vol_winIn_C->SetLineColor(kGray); + // Honeycomb layer + TGeoBBox* winIn_HC = + new TGeoBBox("winIn_HC", -0.3 + activeAreaX / 2., 0.3 + activeAreaY / 2., winIn_HC_thickness / 2.); + TGeoVolume* vol_winIn_HC = new TGeoVolume("vol_winIn_HC", winIn_HC, honeycombVolMed); + vol_winIn_HC->SetLineColor(kOrange); + // framex + TGeoBBox* winIn_fx = + new TGeoBBox("winIn_fx", -0.3 + activeAreaX / 2, WIN_Frame_thickness / 2, winIn_HC_thickness / 2.); + TGeoVolume* vol_winIn_fx = new TGeoVolume("vol_winIn_fx", winIn_fx, frameVolMed); + vol_winIn_fx->SetLineColor(kBlue); + // framey + TGeoBBox* winIn_fy = + new TGeoBBox("winIn_fy", WIN_Frame_thickness / 2, (1.8 + activeAreaY) / 2, winIn_HC_thickness / 2.); + TGeoVolume* vol_winIn_fy = new TGeoVolume("vol_winIn_fy", winIn_fy, frameVolMed); + vol_winIn_fy->SetLineColor(kCyan); + // Add up all components + TGeoVolumeAssembly* trd_win_in = new TGeoVolumeAssembly("EntranceWin"); + trd_win_in->AddNode(vol_winIn_fx, 1, new TGeoTranslation("", 0., 0.6 + activeAreaY / 2., 0)); + trd_win_in->AddNode(vol_winIn_fx, 2, new TGeoTranslation("", 0., -(activeAreaY / 2. + 0.6), 0)); + trd_win_in->AddNode(vol_winIn_fy, 1, new TGeoTranslation("", activeAreaX / 2., 0., 0)); + trd_win_in->AddNode(vol_winIn_fy, 2, new TGeoTranslation("", -activeAreaX / 2., 0., 0)); + + trd_win_in->AddNode(vol_winIn_HC, 1); + trd_win_in->AddNode(vol_winIn_C, 1, + new TGeoTranslation("", 0., 0., 0.5 * (winIn_HC_thickness + winIn_C_thickness))); + // trd_win_in->AddNode(vol_winIn_C, 2, + // new TGeoTranslation("", 0., 0., -(winIn_thickness-winIn_C_thickness)/2.)); + module->AddNode(trd_win_in, 1, + new TGeoTranslation( + "", 0., 0., gasBu_position - gas_thickness / 2. - winIn_C_thickness - winIn_HC_thickness / 2.)); + } + + // Gas. The volume has to be defined only for pads (read-out) area. Take care in the DigiPara definition + TGeoBBox* trd_gas = new TGeoBBox("trd_gas", 0.5 * activeAreaX, 0.5 * activeAreaY, 0.5 * gas_thickness); + TGeoVolume* vol_gas = new TGeoVolume("gas", trd_gas, gasVolMed); + vol_gas->SetLineColor(kRed + 3); //trdmod1_gasvol->SetTransparency(40); + TGeoBBox* trd_gas_dstr = new TGeoBBox("trd_gas_dstr", 0.5 * activeAreaX, 0.2, 0.5 * gas_thickness); + TGeoVolume* vol_gas_dstr = new TGeoVolume("inlet", trd_gas_dstr, gasVolMed); + vol_gas_dstr->SetLineColor(kRed); + module->AddNode(vol_gas, 0, new TGeoTranslation("", 0., 0., gasBu_position)); + module->AddNode(vol_gas_dstr, 0, new TGeoTranslation("", 0., 0.5 * activeAreaY + 0.2, gasBu_position)); + module->AddNode(vol_gas_dstr, 1, new TGeoTranslation("", 0., -0.5 * activeAreaY - 0.2, gasBu_position)); + + const Double_t pp_pads_thickness = 0.0025; + const Double_t pp_pcb_thickness = 0.0360; + const Double_t pp_hc_thickness = 0.2; + const Double_t pp_c_thickness = 0.05; + const Double_t pp_thickness = /*pp_pads_thickness + */ pp_pcb_thickness + pp_hc_thickness + pp_c_thickness; + if (IncludePadplane) { + // Pad Copper + TGeoBBox* trd_pp = new TGeoBBox("pp_cu", activeAreaX / 2., activeAreaY / 2., pp_pads_thickness / 2.); + TGeoVolume* vol_trd_pp = new TGeoVolume("vol_pp_cu", trd_pp, padcopperVolMed); + vol_trd_pp->SetLineColor(kRed); + // Pad Plane + TGeoBBox* trd_ppPCB = new TGeoBBox("pp_pcb", 1.0 + activeAreaX / 2., 0.9 + activeAreaY / 2., pp_pcb_thickness / 2.); + TGeoVolume* vol_trd_ppPCB = new TGeoVolume("vol_pp_pcb", trd_ppPCB, padpcbVolMed); + vol_trd_ppPCB->SetLineColor(kGreen); + // Pad Plane HC + TGeoBBox* trd_ppHC_bd = + new TGeoBBox("pp_hc_bd", 1.0 + activeAreaX / 2., 0.9 + activeAreaY / 2., pp_hc_thickness / 2.); + TGeoBBox* trd_ppHC_fc = new TGeoBBox("pp_hc_fc", 2.4 / 2., 0.8 / 2., (1.e-4 + pp_hc_thickness) / 2.); + addFlatCableHoles("pp_hc"); + TGeoCompositeShape* trd_ppHC = new TGeoCompositeShape("pp_hc", sexpr.Data()); + TGeoVolume* vol_trd_ppHC = new TGeoVolume("vol_pp_hc", trd_ppHC, honeycombVolMed); + vol_trd_ppHC->SetLineColor(kOrange); + // Pad Plane C fiber + TGeoBBox* trd_ppC_bd = new TGeoBBox("pp_c_bd", 1.0 + activeAreaX / 2., 0.9 + activeAreaY / 2., pp_c_thickness / 2.); + TGeoBBox* trd_ppC_fc = new TGeoBBox("pp_c_fc", 2.4 / 2., 0.8 / 2., (1.e-4 + pp_c_thickness) / 2.); + addFlatCableHoles("pp_c"); + TGeoCompositeShape* trd_ppC = new TGeoCompositeShape("pp_c", sexpr.Data()); + TGeoVolume* vol_trd_ppC = new TGeoVolume("vol_pp_c", trd_ppC, carbonVolMed); + vol_trd_ppC->SetLineColor(kGray); + + // Add up all components + TGeoVolumeAssembly* vol_pp = new TGeoVolumeAssembly("PadPlane"); + vol_pp->AddNode(vol_trd_pp, 1, new TGeoTranslation("", 0., 0., -pp_thickness / 2 - pp_pads_thickness / 2)); + vol_pp->AddNode(vol_trd_ppPCB, 1, new TGeoTranslation("", 0., 0., -pp_thickness / 2 + pp_pcb_thickness / 2)); + vol_pp->AddNode(vol_trd_ppHC, 1, + new TGeoTranslation("", 0., 0., -pp_thickness / 2 + pp_pcb_thickness + pp_hc_thickness / 2)); + vol_pp->AddNode(vol_trd_ppC, 1, new TGeoTranslation("", 0., 0., pp_thickness / 2 - pp_c_thickness / 2)); + module->AddNode(vol_pp, 1, + new TGeoTranslation("", 0., 0., gasBu_position + gas_thickness / 2. + pp_thickness / 2.)); + } + + + if (IncludeGasFrame) { + // framex + TGeoBBox* frame_fx0 = new TGeoBBox("frame_fx0", activeAreaX / 2., 0.5 / 2., gas_thickness / 2.); + TGeoVolume* vol_frame_fx0 = new TGeoVolume("vol_frame_fx0", frame_fx0, frameVolMed); + vol_frame_fx0->SetLineColor(kYellow - 2); + Double_t frame_fx1_thickness = winIn_thickness + gas_thickness + pp_thickness; + TGeoBBox* frame_fx1 = new TGeoBBox("frame_fx1", 1. + activeAreaX / 2., 0.3 / 2., frame_fx1_thickness / 2.); + TGeoVolume* vol_frame_fx1 = new TGeoVolume("vol_frame_fx1", frame_fx1, frameVolMed); + vol_frame_fx1->SetLineColor(kViolet); //vol_frame_fx1->SetTransparency(50); + + // framey + TGeoBBox* frame_fy_0 = new TGeoBBox("frame_fy_0", 0.7 / 2., (1.8 + activeAreaY) / 2., winIn_thickness / 2.); + TGeoVolume* vol_frame_fy_0 = new TGeoVolume("vol_frame_fy_0", frame_fy_0, frameVolMed); + vol_frame_fy_0->SetLineColor(kBlue); + TGeoBBox* frame_fy_1 = + new TGeoBBox("frame_fy_1", 1.0 / 2., (1.8 + activeAreaY) / 2., 0.4 / 2.); // catode wire support + TGeoVolume* vol_frame_fy_1 = new TGeoVolume("vol_frame_fy_1", frame_fy_1, frameVolMed); + vol_frame_fy_1->SetLineColor(kBlue - 3); + TGeoBBox* frame_fy_2 = new TGeoBBox("frame_fy_2", 0.7 / 2., (1.8 + activeAreaY) / 2., + 0.4 / 2.); // anode wire support + TGeoVolume* vol_frame_fy_2 = new TGeoVolume("vol_frame_fy_2", frame_fy_2, frameVolMed); + vol_frame_fy_2->SetLineColor(kOrange + 4); + TGeoBBox* frame_fy_3 = new TGeoBBox("frame_fy_3", 0.4 / 2., (1.8 + activeAreaY) / 2., + 0.4 / 2.); // pad-plane support + TGeoVolume* vol_frame_fy_3 = new TGeoVolume("vol_frame_fy_3", frame_fy_3, frameVolMed); + vol_frame_fy_3->SetLineColor(kYellow + 3); + // add up framey components + TGeoVolumeAssembly* vol_frame_fy0 = + new TGeoVolumeAssembly("vol_frame_fy0"); // the mother volume of wire support ledge + vol_frame_fy0->AddNode(vol_frame_fy_0, 1, + new TGeoTranslation("", -0.3 - 0.7 / 2., 0., -(0.4 * 1.5 + winIn_thickness / 2.))); + vol_frame_fy0->AddNode(vol_frame_fy_1, 1, new TGeoTranslation("", -1.0 / 2., 0., -0.4)); + vol_frame_fy0->AddNode(vol_frame_fy_2, 1, new TGeoTranslation("", -0.7 / 2., 0., 0.)); + vol_frame_fy0->AddNode(vol_frame_fy_3, 1, new TGeoTranslation("", -0.4 / 2., 0., 0.4)); + TGeoBBox* frame_fy1 = new TGeoBBox("frame_fy1", 0.3 / 2., 1.2 + activeAreaY / 2., frame_fx1_thickness / 2.); + TGeoVolume* vol_frame_fy1 = new TGeoVolume("vol_frame_fy1", frame_fy1, frameVolMed); + vol_frame_fy1->SetLineColor(kViolet + 2); //vol_frame_fy1->SetTransparency(50); + + // Add up all frames + Double_t frame_fx1_position = -winIn_thickness - gas_thickness / 2. + frame_fx1_thickness / 2.; + TGeoVolumeAssembly* trd_gas_frame = new TGeoVolumeAssembly("Frame"); // the mother volume of gas frame + trd_gas_frame->AddNode(vol_frame_fx0, 1, new TGeoTranslation("", 0., activeAreaY / 2. + 0.4 + 0.5 / 2, 0)); + trd_gas_frame->AddNode(vol_frame_fx0, 2, new TGeoTranslation("", 0., -(activeAreaY / 2. + 0.4 + 0.5 / 2), 0)); + trd_gas_frame->AddNode(vol_frame_fx1, 1, + new TGeoTranslation("", 0., activeAreaY / 2. + 0.4 + 0.5 + 0.3 / 2, frame_fx1_position)); + trd_gas_frame->AddNode(vol_frame_fx1, 2, + new TGeoTranslation("", 0., -(activeAreaY / 2. + 0.4 + 0.5 + 0.3 / 2), frame_fx1_position)); + trd_gas_frame->AddNode(vol_frame_fy0, 1, new TGeoTranslation("", -activeAreaX / 2., 0., 0)); + TGeoRotation* fy_rot = new TGeoRotation(); + fy_rot->RotateZ(180.); + TGeoTranslation* fy_tra = new TGeoTranslation("", -activeAreaX / 2., 0., 0); + TGeoHMatrix* fy_transform = new TGeoHMatrix(""); + (*fy_transform) = (*fy_rot) * (*fy_tra); + trd_gas_frame->AddNode(vol_frame_fy0, 2, fy_transform); + trd_gas_frame->AddNode(vol_frame_fy1, 1, + new TGeoTranslation("", activeAreaX / 2. + 1.0 + 0.3 / 2, 0, frame_fx1_position)); + trd_gas_frame->AddNode(vol_frame_fy1, 2, + new TGeoTranslation("", -(activeAreaX / 2. + 1.0 + 0.3 / 2), 0, frame_fx1_position)); + module->AddNode(trd_gas_frame, 1, new TGeoTranslation("", 0., 0., gasBu_position)); + } + + + const Double_t bp_hc_thickness = 2.; + const Double_t bp_pcb_thickness = 0.05; + const Double_t bp_cu_thickness = 0.003; + const Double_t bp_thickness = bp_cu_thickness + bp_hc_thickness + bp_pcb_thickness; + const Double_t bp_position = gasBu_position + 0.5 * gas_thickness + pp_thickness; + if (IncludeBackpanel) { + // Honeycomb board and flat-cable hole + TGeoBBox* bp_hc_bd = new TGeoBBox("bp_hc_bd", activeAreaX / 2., activeAreaY / 2., bp_hc_thickness / 2.); + TGeoBBox* bp_hc_fc = new TGeoBBox("bp_hc_fc", 2.4 / 2., 0.8 / 2., (1.e-4 + bp_hc_thickness) / 2.); + addFlatCableHoles("bp_hc"); + TGeoCompositeShape* bp_hc = new TGeoCompositeShape("bp_hc", sexpr.Data()); + TGeoVolume* vol_bp_hc = new TGeoVolume("vol_bp_hc", bp_hc, honeycombVolMed); + vol_bp_hc->SetLineColor(kOrange); + // Screen fibre-glass support (PCB) + TGeoBBox* bp_pcb_bd = + new TGeoBBox("bp_pcb_bd", 0.5 + activeAreaX / 2., 0.5 + activeAreaY / 2., bp_pcb_thickness / 2.); + TGeoBBox* bp_pcb_fc = new TGeoBBox("bp_pcb_fc", 2.4 / 2., 0.8 / 2., (1.e-3 + bp_pcb_thickness) / 2.); + addFlatCableHoles("bp_pcb"); + TGeoCompositeShape* bp_pcb = new TGeoCompositeShape("bp_pcb", sexpr.Data()); + TGeoVolume* vol_bp_pcb = new TGeoVolume("vol_bp_pcb", bp_pcb, padpcbVolMed); + vol_bp_pcb->SetLineColor(kGreen); + // Pad Copper + TGeoBBox* bp_cu_bd = new TGeoBBox("bp_cu_bd", 0.5 + activeAreaX / 2., 0.5 + activeAreaY / 2., bp_cu_thickness / 2.); + TGeoBBox* bp_cu_fc = new TGeoBBox("bp_cu_fc", 2.4 / 2., 0.8 / 2., (1.e-3 + bp_cu_thickness) / 2.); + addFlatCableHoles("bp_cu"); + TGeoCompositeShape* bp_cu = new TGeoCompositeShape("bp_cu", sexpr.Data()); + TGeoVolume* vol_bp_cu = new TGeoVolume("vol_bp_cu", bp_cu, padcopperVolMed); + vol_bp_cu->SetLineColor(kRed); + + TGeoBBox* bp_fx = new TGeoBBox("bp_fx", activeAreaX / 2., 0.5 / 2., bp_hc_thickness / 2.); + TGeoVolume* vol_bp_fx = new TGeoVolume("vol_bp_fx", bp_fx, frameVolMed); + vol_bp_fx->SetLineColor(kViolet); //vol_gas_fx1->SetTransparency(50); + TGeoBBox* bp_fy = new TGeoBBox("bp_fy", 0.5 / 2, 0.5 + 0.5 * activeAreaY, bp_hc_thickness / 2.); + TGeoVolume* vol_bp_fy = new TGeoVolume("vol_bp_fy", bp_fy, frameVolMed); + vol_bp_fy->SetLineColor(kViolet + 2); + + // Add up all components + TGeoVolumeAssembly* trd_supp = new TGeoVolumeAssembly("BackPanel"); + trd_supp->AddNode(vol_bp_hc, 1); + trd_supp->AddNode(vol_bp_pcb, 1, new TGeoTranslation("", 0., 0., 0.5 * (bp_hc_thickness + bp_pcb_thickness))); + trd_supp->AddNode( + vol_bp_cu, 1, new TGeoTranslation("", 0., 0., 0.5 * (bp_hc_thickness + 2 * bp_pcb_thickness + bp_cu_thickness))); + trd_supp->AddNode(vol_bp_fx, 1, new TGeoTranslation("", 0., 0.5 * (0.5 + activeAreaY), 0)); + trd_supp->AddNode(vol_bp_fx, 2, new TGeoTranslation("", 0., -0.5 * (0.5 + activeAreaY), 0)); + trd_supp->AddNode(vol_bp_fy, 1, new TGeoTranslation("", 0.5 * (0.5 + activeAreaX), 0., 0.)); + trd_supp->AddNode(vol_bp_fy, 2, new TGeoTranslation("", -0.5 * (0.5 + activeAreaX), 0., 0.)); + module->AddNode( + trd_supp, 1, + new TGeoTranslation("", 0., 0., gasBu_position + 0.5 * gas_thickness + pp_thickness + 0.5 * bp_hc_thickness)); + } + + // FEBs + // ROB FASP + const Double_t FASPRO_zspace = 1.5; // gap size between boards + const Double_t FASPRO_length = 17.9; // length of FASP FEBs in cm + const Double_t FASPRO_width = 5.12; // width of FASP FEBs in cm + const Double_t FASPRO_dx = 0.01; // + const Double_t FASPRO_dy = 0.28; // + const Double_t FASPRO_thickness = 0.17; + const Double_t FASPRO_position = bp_position + bp_thickness + FASPRO_zspace; + const Double_t GETS_length = 13.9; // length of PolarFire FEBs in cm + const Double_t GETS_width = 5.12; // width of PolarFire FEBs in cm + const Double_t GETS_thickness = 0.2; + const Double_t LVB_length = 5.; // length of LV FEBs in cm + const Double_t LVB_width = 20.; // width of LV FEBs in cm + const Double_t LVB_thickness = 0.1; + + // ASIC parameters + const Double_t fasp_size[] = {1.2, 1.2, 0.2}; // FASP package and interposer size 1.5x1.5 cm2 + const Double_t faspConn_size[] = {2.1, 0.3, 0.6}; // FASP package and interposer size 1.5x1.5 cm2 + const Double_t fasp_xoffset = 6.0; // ASIC offset from ROC middle (horizontally) + const Double_t fasp_yoffset = 1.35; // ASIC offset from DET connector (vertical) + const Double_t fpga_size[] = {1.2, 1.2, 0.2}; // PolarFire FPGA package size 1.5x1.5 cm2 + // FMC+ connector definition + const Double_t FMCwidth = 2.0; // width of a MF FMC connector + const Double_t FMClength = 5.6; // length of a MF FMC connector + const Double_t FMCheight = 1.13; // height of a MF FMC connector + const Double_t FMCsuppD = 0.8; // outer radius of FMC connector side supports + const Double_t FMCsuppX = 0.6; // FMC connector side supports + // GETS2C-ROB3 connector boord parameters + const Double_t robConn_size_x = 3.9; //15.0; + const Double_t robConn_size_y = 15.0; + // const Double_t robConn_xoffset = 6.0; + if (IncludeFebs) { + // Create all FEBs and place them in an assembly which will be added to the TRD module + TGeoBBox* faspro_bd = new TGeoBBox("faspro_bd", FASPRO_length / 2., FASPRO_width / 2., FASPRO_thickness / 2.); + TGeoVolume* vol_faspro_bd = new TGeoVolume("vol_faspro_bd", faspro_bd, febVolMed); // the FEB made of PCB + vol_faspro_bd->SetLineColor(kGreen + 3); //vol_faspro_bd->SetTransparency(50); + TGeoBBox* gets_bd = new TGeoBBox("gets_bd", GETS_length / 2., GETS_width / 2., GETS_thickness / 2.); + TGeoVolume* vol_gets_bd = new TGeoVolume("vol_gets_bd", gets_bd, febVolMed); // the FEB made of PCB + vol_gets_bd->SetLineColor(kGreen + 8); //vol_gets_bd->SetTransparency(50); + // Create the FMC connector + TGeoBBox* fmc_conn = new TGeoBBox("fmc_conn", 0.5 * FMClength, 0.5 * FMCwidth, 0.5 * FMCheight); + TGeoVolume* vol_fmc_conn = new TGeoVolume("vol_fmc_conn", fmc_conn, febVolMed); // the FMC made of PCB + vol_fmc_conn->SetLineColor(kGray + 2); + TGeoTube* fmc_connSupp = new TGeoTube("fmc_connSupp", 0, 0.5 * FMCsuppD, 0.5 * FMCheight); + TGeoVolume* vol_fmc_connSupp = new TGeoVolume("vol_fmc_connSupp", fmc_connSupp, aluminiumVolMed); // support Al + vol_fmc_connSupp->SetLineColor(kGray); + TGeoVolumeAssembly* fmc_connect = new TGeoVolumeAssembly("FMC"); + fmc_connect->AddNode(vol_fmc_conn, 1); + fmc_connect->AddNode(vol_fmc_connSupp, 1, new TGeoTranslation("", 0.5 * FMClength + FMCsuppX, 0, 0.)); + fmc_connect->AddNode(vol_fmc_connSupp, 2, new TGeoTranslation("", -(0.5 * FMClength + FMCsuppX), 0, 0.)); + // Add up all elements of FASPRO + TGeoVolumeAssembly* faspro = new TGeoVolumeAssembly("FASPRO"); + faspro->AddNode(vol_faspro_bd, 1); + faspro->AddNode(fmc_connect, 0, new TGeoTranslation("", 0, 0, 0.5 * FMCheight + 0.5 * FASPRO_thickness)); + Double_t GETS_zpos = 0.5 * FASPRO_thickness + FMCheight + 0.5 * GETS_thickness; + faspro->AddNode(vol_gets_bd, 1, new TGeoTranslation("", 0, 0, GETS_zpos)); + + // ASICs + if (IncludeAsics) { + TGeoBBox* fasp_asic = new TGeoBBox("fasp_asic", 0.5 * fasp_size[0], 0.5 * fasp_size[1], 0.5 * fasp_size[2]); + TGeoVolume* vol_fasp_asic = new TGeoVolume("FASP", fasp_asic, padpcbVolMed); + vol_fasp_asic->SetLineColor(kBlack); + TGeoBBox* fasp_conn = + new TGeoBBox("fasp_conn", 0.5 * faspConn_size[0], 0.5 * faspConn_size[1], 0.5 * faspConn_size[2]); + TGeoVolume* vol_fasp_conn = new TGeoVolume("fasp_conn", fasp_conn, padpcbVolMed); + vol_fasp_conn->SetLineColor(kRed + 4); + for (Int_t cAsic(-1), iAsic(0); cAsic <= 1; cAsic++) { + faspro->AddNode(vol_fasp_asic, iAsic, + new TGeoTranslation("", cAsic * fasp_xoffset, fasp_yoffset, + -1 * (0.5 * FASPRO_thickness + 0.5 * fasp_size[2]))); + faspro->AddNode(vol_fasp_conn, iAsic, + new TGeoTranslation("", cAsic * fasp_xoffset, 0.5 * FASPRO_width - 0.2 - 0.5 * faspConn_size[1], + -1 * (0.5 * FASPRO_thickness + 0.5 * faspConn_size[2]))); + iAsic++; + faspro->AddNode(vol_fasp_asic, iAsic, + new TGeoTranslation("", cAsic * fasp_xoffset, -fasp_yoffset, + -1 * (0.5 * FASPRO_thickness + 0.5 * fasp_size[2]))); + faspro->AddNode(vol_fasp_conn, iAsic, + new TGeoTranslation("", cAsic * fasp_xoffset, + -(0.5 * FASPRO_width - 0.2 - 0.5 * faspConn_size[1]), + -1 * (0.5 * FASPRO_thickness + 0.5 * faspConn_size[2]))); + iAsic++; + } + + TGeoBBox* fpga_asic = new TGeoBBox("fpga_asic", 0.5 * fpga_size[0], 0.5 * fpga_size[1], 0.5 * fpga_size[2]); + TGeoVolume* vol_fpga_asic = new TGeoVolume("FPGA", fpga_asic, asicVolMed); + vol_fpga_asic->SetLineColor(kBlack); + faspro->AddNode(vol_fpga_asic, 0, + new TGeoTranslation("", 0, -fasp_yoffset, GETS_zpos + 0.5 * GETS_thickness + 0.5 * fpga_size[2])); + faspro->AddNode(vol_fpga_asic, 1, + new TGeoTranslation("", 0, fasp_yoffset, GETS_zpos + 0.5 * GETS_thickness + 0.5 * fpga_size[2])); + } + // supports for electronics + TGeoBBox* faspro_fy = new TGeoBBox("faspro_fy", 0.4 / 2, 0.5 + 0.5 * activeAreaY, 0.5 * FASPRO_zspace); + TGeoVolume* vol_faspro_fy = new TGeoVolume("faspro_fy", faspro_fy, frameVolMed); + vol_faspro_fy->SetLineColor(kViolet + 2); //vol_faspro_fy->SetTransparency(50); + + // now go on with FEB placement + Int_t cFeb(-1); + TGeoVolumeAssembly* vol_feb = new TGeoVolumeAssembly("FEB"); // the mother volume of all FEBs + for (Int_t iFeb(0); cFeb < 2; cFeb++) { + vol_feb->AddNode(vol_faspro_fy, cFeb + 1, + new TGeoTranslation("", (cFeb - 0.5) * (FASPRO_length + FASPRO_dx), 0., + -0.5 * (FASPRO_thickness + FASPRO_zspace))); + for (Int_t rFeb(0); rFeb < 5; rFeb++) { + // the upper side ... + vol_feb->AddNode( + faspro, iFeb++, + new TGeoTranslation("", cFeb * (FASPRO_length + FASPRO_dx), (rFeb + 0.5) * (FASPRO_width + FASPRO_dy), 0)); + // the bottom side ... + vol_feb->AddNode( + faspro, iFeb++, + new TGeoTranslation("", cFeb * (FASPRO_length + FASPRO_dx), -(rFeb + 0.5) * (FASPRO_width + FASPRO_dy), 0)); + } + } + vol_feb->AddNode(vol_faspro_fy, cFeb + 1, + new TGeoTranslation("", (cFeb - 0.5) * (FASPRO_length + FASPRO_dx), 0., + -0.5 * (FASPRO_thickness + FASPRO_zspace))); + + // add LV regulators boards + Double_t LVB_pos = FMCheight + 0.5 * (FASPRO_thickness + LVB_thickness); + TGeoBBox* lv_bd = new TGeoBBox("lv_bd", LVB_length / 2., LVB_width / 2., LVB_thickness / 2.); + TGeoVolume* vol_lv_bd = new TGeoVolume("lv_bd", lv_bd, febVolMed); // the LV board made of PCB + vol_lv_bd->SetLineColor(kGreen - 3); + vol_feb->AddNode( + vol_lv_bd, 0, + new TGeoTranslation("", 0., 0.5 + 0.5 * (activeAreaY - LVB_width), LVB_pos + FMCheight + 0.5 * LVB_thickness)); + vol_feb->AddNode( + vol_lv_bd, 1, + new TGeoTranslation("", 0., -0.5 + 0.5 * (-activeAreaY + LVB_width), LVB_pos + FMCheight + 0.5 * LVB_thickness)); + + if (IncludeRobs) { + TGeoVolumeAssembly* crob = new TGeoVolumeAssembly("C-ROB"); + TGeoBBox* crob_bd = new TGeoBBox("crob_bd", rob_size_x / 2., rob_size_y / 2., rob_thickness / 2.); + TGeoVolume* vol_crob_bd = new TGeoVolume("crob_bd", crob_bd, febVolMed); // the ROB made of PCB + vol_crob_bd->SetLineColor(kRed + 8); // set color + TGeoRotation* crob_fmc_rot = new TGeoRotation("crob_fmc_rot"); + crob_fmc_rot->RotateZ(90.); + crob_fmc_rot->RegisterYourself(); + TGeoTranslation* crob_fmc_tra = new TGeoTranslation("crob_fmc_tra", 0., 0.5 * (FMCwidth - robConn_size_x) + 0.2, + 0.5 * (FMCheight + rob_thickness)); + crob_fmc_tra->RegisterYourself(); + TGeoHMatrix* crob_fmc_transform = new TGeoHMatrix(""); + (*crob_fmc_transform) = (*crob_fmc_rot) * (*crob_fmc_tra); + // Add GETS - CROB interface + TGeoBBox* crob_addapt = new TGeoBBox("crob_addapt", robConn_size_x / 2., robConn_size_y / 2., rob_thickness / 2.); + TGeoVolume* vol_crob_addapt = new TGeoVolume("crob_addapt", crob_addapt, febVolMed); // the ROB made of PCB + vol_crob_addapt->SetLineColor(kRed + 6); // set color + crob->AddNode(vol_crob_addapt, 0); + crob->AddNode(fmc_connect, 1, crob_fmc_transform); + crob->AddNode(vol_crob_bd, 1, + new TGeoTranslation("", -0.5 * (rob_size_x - robConn_size_x) + 1.5, 0., FMCheight + rob_thickness)); + + // GBTXs + TGeoBBox* crob_gbtx = new TGeoBBox("crob_gbtx", gbtx_width / 2., gbtx_width / 2., gbtx_thickness / 2.); + TGeoVolume* vol_crob_gbtx = new TGeoVolume("crob_gbtx", crob_gbtx, asicVolMed); + vol_crob_gbtx->SetLineColor(kGreen); + //place 3 GBTXs on each C-ROC + Double_t gbtx_pos_x = 0.5 * (-rob_size_x + gbtx_width) - 1.5 /*-0.5*/; + Double_t gbtx_pos_y = 0.5 * (rob_size_y - gbtx_width) - 0.5; + crob->AddNode(vol_crob_gbtx, 0, + new TGeoTranslation("", gbtx_pos_x, gbtx_pos_y, FMCheight + rob_thickness + 0.5 * gbtx_thickness)); + crob->AddNode(vol_crob_gbtx, 1, + new TGeoTranslation("", gbtx_pos_x, -gbtx_pos_y, FMCheight + rob_thickness + 0.5 * gbtx_thickness)); + crob->AddNode(vol_crob_gbtx, 2, + new TGeoTranslation("", gbtx_pos_x + 5., 0., FMCheight + rob_thickness + 0.5 * gbtx_thickness)); + + // now go on with ROB placement + Int_t nofRobs = RobsPerModule[moduleType], nofRobsHalf(nofRobs / 2); + for (Int_t iRob = 0, jRob(0); iRob < nofRobsHalf; iRob++) { + Double_t rob_pos = (iRob + 0.5) / nofRobsHalf - 0.5, // equal spacing of ROBs on the backpanel + rob_pos_y = rob_pos * activeAreaY; + vol_feb->AddNode(crob, jRob++, new TGeoTranslation("", -0.5 * (FASPRO_length + FASPRO_dx), rob_pos_y, LVB_pos)); + TGeoRotation* crob_rot = new TGeoRotation("crob_rot"); + crob_rot->RotateZ(180.); + crob_rot->RegisterYourself(); + TGeoTranslation* crob_tra = + new TGeoTranslation("crob_tra", 0.5 * (FASPRO_length + FASPRO_dx), rob_pos_y, LVB_pos); + crob_tra->RegisterYourself(); + TGeoHMatrix* crob_transform = new TGeoHMatrix(""); + (*crob_transform) = (*crob_tra) * (*crob_rot); + vol_feb->AddNode(crob, jRob++, crob_transform); + } + } // IncludeGbtx + + // put FEB box on module + module->AddNode(vol_feb, 1, + new TGeoTranslation("", 0., 0., + FASPRO_position)); // put febvolume at correct z position wrt to the module + } + + return module; +} + +TGeoVolume* create_support_inner() +{ + Double_t sizeX = DetectorSizeX[0]; + Double_t sizeY = DetectorSizeY[0]; + TGeoMedium* frameVolMed = gGeoMan->GetMedium(FrameVolumeMedium); + TGeoMedium* aluminiumVolMed = gGeoMan->GetMedium(AluminiumVolumeMedium); + + // wall support + TGeoTranslation* tr(NULL); + TGeoBBox* wall_al_b = new TGeoBBox("wall_al_b", 0.5 * 4 * sizeX, 1., 1.); + TGeoBBox* wall_fr4 = new TGeoBBox("wall_fr4", 1.e-4 + 0.5 * 4 * sizeX, 0.8, 0.8); + TGeoVolume* vol_wall_fr4 = new TGeoVolume("wall_fr4", wall_fr4, frameVolMed); + vol_wall_fr4->SetLineColor(kBlue - 9); + TGeoCompositeShape* wall_al = new TGeoCompositeShape("wall_al", "wall_al_b-wall_fr4"); + TGeoVolume* vol_wall_al = new TGeoVolume("wall_al", wall_al, aluminiumVolMed); + vol_wall_al->SetLineColor(kGray); + TGeoVolumeAssembly* bar = new TGeoVolumeAssembly("innerSupport"); + bar->AddNode(vol_wall_al, 1); + bar->AddNode(vol_wall_fr4, 1); + return bar; +} + + +Int_t copy_nr(Int_t stationNr, Int_t copyNr, Int_t isRotated, Int_t planeNr, Int_t modinplaneNr) +{ + //printf("stationNr[%d] copyNr[%d] isRotated[%d] planeNr[%d] modinplaneNr[%d]\n", stationNr, copyNr, isRotated, planeNr, modinplaneNr); + + if (modinplaneNr > 128) + printf("Warning: too many modules in this layer %02d (max 128 according to " + "CbmTrdAddress)\n", + planeNr); + + return (stationNr * 100000000 // 1 digit + + copyNr * 1000000 // 2 digit + + isRotated * 100000 // 1 digit + + planeNr * 1000 // 2 digit + + modinplaneNr * 1); // 3 digit +} + +void create_detector_layers(Int_t layerId) +{ + Int_t module_id = 0; + Int_t layerType = LayerType[layerId] / 10; // this is also a station number + Int_t isRotated = LayerType[layerId] % 10; // is 1 for layers 2,4, ... + TGeoRotation* module_rotation = new TGeoRotation(); + + Int_t stationNr = layerType; + + // rotation is now done in the for loop for each module individually + // if ( isRotated == 1 ) { + // module_rotation = new TGeoRotation(); + // module_rotation->RotateZ(90.); + // } else { + // module_rotation = new TGeoRotation(); + // module_rotation->RotateZ( 0.); + // } + + Int_t innerarray_size1 = LayerArraySize[layerType - 1][0]; + Int_t innerarray_size2 = LayerArraySize[layerType - 1][1]; + const Int_t* innerLayer; + + Int_t outerarray_size1 = LayerArraySize[layerType - 1][2]; + Int_t outerarray_size2 = LayerArraySize[layerType - 1][3]; + const Int_t* outerLayer; + + if (1 == layerType) { + innerLayer = (Int_t*) layer1i; + outerLayer = (Int_t*) layer1o; + } + else if (2 == layerType) { + innerLayer = (Int_t*) layer2i; + outerLayer = (Int_t*) layer2o; + } + else if (3 == layerType) { + innerLayer = (Int_t*) layer3i; + outerLayer = (Int_t*) layer3o; + } + else { + std::cout << "Type of layer not known" << std::endl; + } + + // add layer keeping volume + TString layername = Form("layer%02d", PlaneId[layerId]); + TGeoVolume* layer = new TGeoVolumeAssembly(layername); + + // compute layer copy number + Int_t i = LayerType[layerId] / 10 * 10000 // 1 digit // fStation + + LayerType[layerId] % 10 * 1000 // 1 digit // isRotated + + LayerNrInStation[layerId] * 100 // 1 digit // fLayer + + PlaneId[layerId]; // 2 digits // fPlane // layer type as leading digit in copy number of layer + gGeoMan->GetVolume(geoVersion)->AddNode(layer, i); + + // Int_t i = 100 + PlaneId[layerId]; + // gGeoMan->GetVolume(geoVersion)->AddNode(layer, 1); + // cout << layername << endl; + + Double_t ExplodeScale = 1.00; + if (DoExplode) // if explosion, set scale + ExplodeScale = ExplodeFactor; + + Int_t modId = 0; // module id, only within this layer + + Int_t copyNr[NofModuleTypes] = {0}; // copy number for each module type + for (Int_t type = 1; type <= NofModuleTypes; type++) { + if (type > 4 && type < 9) continue; + for (Int_t j = (innerarray_size1 - 1); j >= 0; j--) { // start from the bottom + for (Int_t i = 0; i < innerarray_size2; i++) { + module_id = *(innerLayer + (j * innerarray_size2 + i)); + if (module_id / 100 == type) { + Float_t y = -(j - 4); + Float_t x = i - 1.5; + + // displacement + Double_t dx = 0; + Double_t dy = 0; + Double_t dz = 0; + + if (DisplaceRandom) { + dx = (r3.Rndm() - .5) * 2 * maxdx; // max +- 0.1 cm shift + dy = (r3.Rndm() - .5) * 2 * maxdy; // max +- 0.1 cm shift + dz = (r3.Rndm() - .5) * 2 * maxdz; // max +- 1.0 cm shift + } + + Double_t xPos = DetectorSizeX[0] * x * ExplodeScale + dx; + Double_t yPos = DetectorSizeY[0] * y * ExplodeScale + dy; + copyNr[type - 1]++; + modId++; + + // statistics per layer and module type + ModuleStats[layerId][type - 1]++; + + // Int_t copy = copy_nr_modid(stationNr, layerNrInStation, copyNrIn[type - 1], PlaneId[layerId], modId); // with modID + // Int_t copy = copy_nr(stationNr, copyNrIn[type - 1], isRotated, PlaneId[layerId], modId); + + // take care of FEB orientation - away from beam + Int_t copy = 0; + module_rotation = new TGeoRotation(); // need to renew rotation to start from 0 degree angle + if (isRotated == 0) // layer 1,3 ... + { + copy = copy_nr(stationNr, copyNr[type - 1], module_id / 10 % 10, PlaneId[layerId], modId); + module_rotation->RotateZ( + (module_id / 10 % 10) * 90.); // rotate module by 0 or 180 degrees, see layer[1-3][i,o] - vertical pads + } + else // layer 2,4 ... + { + copy = copy_nr(stationNr, copyNr[type - 1], module_id % 10, PlaneId[layerId], modId); + module_rotation->RotateZ( + (module_id % 10) * 90.); // rotate module by 90 or 270 degrees, see layer[1-3][i,o] - horizontal pads + } + + // rotation + Double_t drotx = 0; + Double_t droty = 0; + Double_t drotz = 0; + + if (RotateRandom) { + drotx = (r3.Rndm() - .5) * 2 * maxdrotx; + droty = (r3.Rndm() - .5) * 2 * maxdroty; + drotz = (r3.Rndm() - .5) * 2 * maxdrotz; + + module_rotation->RotateZ(drotz); + module_rotation->RotateY(droty); + module_rotation->RotateX(drotx); + } + + TGeoCombiTrans* module_placement = + new TGeoCombiTrans(xPos, yPos, LayerPosition[layerId] + LayerThickness / 2 + dz, + module_rotation); // shift by half layer thickness + // gGeoMan->GetVolume(geoVersion)->AddNode(gModules[type - 1], copy, module_placement); + // add module to layer + printf("%s [%p]: type[%d] copy[%d]\n", layername.Data(), (void*) gModules[type - 1], type, copy); + gGeoMan->GetVolume(layername)->AddNode(gModules[type - 1], copy, module_placement); + } + } + } + } + + for (Int_t type = 5; type <= 8; type++) { + for (Int_t j = (outerarray_size1 - 1); j >= 0; j--) { // start from the bottom + for (Int_t i = 0; i < outerarray_size2; i++) { + module_id = *(outerLayer + (j * outerarray_size2 + i)); + if (module_id / 100 == type) { + Float_t y = -(j - 4); + Float_t x = i - 5; + + // displacement + Double_t dx = 0; + Double_t dy = 0; + Double_t dz = 0; + + if (DisplaceRandom) { + dx = (r3.Rndm() - .5) * 2 * maxdx; // max +- 0.1 cm shift + dy = (r3.Rndm() - .5) * 2 * maxdy; // max +- 0.1 cm shift + dz = (r3.Rndm() - .5) * 2 * maxdz; // max +- 1.0 cm shift + } + + // Double_t xPos = DetectorSizeX[1] * x * ExplodeScale + dx; + Double_t xPos = 0; + //cout << "x before: " << x ; + if (x > 0) { + x += -2 + 0.5; + xPos = 2 * DetectorSizeX[0] + DetectorSizeX[1] * x * ExplodeScale + dx; + } + else { + x += +2 - 0.5; + xPos = -2 * DetectorSizeX[0] + DetectorSizeX[1] * x * ExplodeScale + dx; + } + //cout << " x after: " << x << endl; + Double_t yPos = DetectorSizeY[1] * y * ExplodeScale + dy; + copyNr[type - 1]++; + modId++; + + // statistics per layer and module type + ModuleStats[layerId][type - 1]++; + + // Int_t copy = copy_nr_modid(stationNr, layerNrInStation, copyNrOut[type - 5], PlaneId[layerId], modId); // with modID + // Int_t copy = copy_nr(stationNr, copyNrOut[type - 5], isRotated, PlaneId[layerId], modId); + + // take care of FEB orientation - away from beam + Int_t copy = 0; + module_rotation = new TGeoRotation(); // need to renew rotation to start from 0 degree angle + if (isRotated == 0) // layer 1,3 ... + { + copy = copy_nr(stationNr, copyNr[type - 1], module_id / 10 % 10, PlaneId[layerId], modId); + module_rotation->RotateZ( + (module_id / 10 % 10) * 90.); // rotate module by 0 or 180 degrees, see layer[1-3][i,o] - vertical pads + } + else // layer 2,4 ... + { + copy = copy_nr(stationNr, copyNr[type - 1], module_id % 10, PlaneId[layerId], modId); + module_rotation->RotateZ( + (module_id % 10) * 90.); // rotate module by 90 or 270 degrees, see layer[1-3][i,o] - horizontal pads + } + + // rotation + Double_t drotx = 0; + Double_t droty = 0; + Double_t drotz = 0; + + if (RotateRandom) { + drotx = (r3.Rndm() - .5) * 2 * maxdrotx; + droty = (r3.Rndm() - .5) * 2 * maxdroty; + drotz = (r3.Rndm() - .5) * 2 * maxdrotz; + + module_rotation->RotateZ(drotz); + module_rotation->RotateY(droty); + module_rotation->RotateX(drotx); + } + + TGeoCombiTrans* module_placement = + new TGeoCombiTrans(xPos, yPos, LayerPosition[layerId] + LayerThickness / 2 + dz, + module_rotation); // shift by half layer thickness + // gGeoMan->GetVolume(geoVersion)->AddNode(gModules[type - 1], copy, module_placement); + // add module to layer + gGeoMan->GetVolume(layername)->AddNode(gModules[type - 1], copy, module_placement); + } + } + } + } + + // add support structure for Bucharest inner-zone + Double_t sizeY = DetectorSizeY[0]; + TGeoVolume* inner = create_support_inner(); + for (Int_t ib(0); ib < 4; ib++) { + layer->AddNode(inner, ib + 1, + new TGeoTranslation("", 0., (1.5 - ib) * sizeY, + LayerPosition[layerId] + LayerThickness / 2 + gasBu_position + + 0.5 * gas_thickness + 0.286 + 1.)); + } +} + + +void create_mag_field_vector() +{ + const TString cbmfield_01 = "cbm_field"; + TGeoVolume* cbmfield_1 = new TGeoVolumeAssembly(cbmfield_01); + TGeoMedium* copperVolMed = gGeoMan->GetMedium(PadCopperVolumeMedium); // define Volume Medium + TGeoRotation* rotx090 = new TGeoRotation("rotx090"); + rotx090->RotateX(90.); // rotate 90 deg around x-axis + TGeoRotation* rotx270 = new TGeoRotation("rotx270"); + rotx270->RotateX(270.); // rotate 270 deg around x-axis + + Int_t tube_length = 500; + Int_t cone_length = 120; + Int_t cone_width = 280; + + // field tube + TGeoTube* trd_field = new TGeoTube("", 0., 100 / 2., tube_length / 2.); + TGeoVolume* trdmod1_fieldvol = new TGeoVolume("tube", trd_field, copperVolMed); + trdmod1_fieldvol->SetLineColor(kRed); + trdmod1_fieldvol->SetTransparency(30); // transparency for the TRD + TGeoTranslation* trd_field_trans = new TGeoTranslation("", 0., 0., 0.); // tube position + cbmfield_1->AddNode(trdmod1_fieldvol, 1, trd_field_trans); + + // field cone + TGeoCone* trd_cone = new TGeoCone("", cone_length / 2., 0., cone_width / 2., 0., 0.); + TGeoVolume* trdmod1_conevol = new TGeoVolume("cone", trd_cone, copperVolMed); + trdmod1_conevol->SetLineColor(kRed); + trdmod1_conevol->SetTransparency(30); // transparency for the TRD + TGeoTranslation* trd_cone_trans = new TGeoTranslation("", 0., 0., (tube_length + cone_length) / 2.); // cone position + cbmfield_1->AddNode(trdmod1_conevol, 1, trd_cone_trans); + + TGeoCombiTrans* field_combi01 = new TGeoCombiTrans(0., 0., 40., rotx270); // point in +y direction + gGeoMan->GetVolume(geoVersion)->AddNode(cbmfield_1, 1, field_combi01); + + // TGeoCombiTrans* field_combi02 = new TGeoCombiTrans( 200., 0., 0., rotx090); // point in -y direction + // gGeoMan->GetVolume(geoVersion)->AddNode(cbmfield_1, 2, field_combi02); +} + + +void create_power_bars_vertical() +{ + const TString power_01 = "power_bars_trd1"; + TGeoVolume* power_1 = new TGeoVolumeAssembly(power_01); + + TGeoBBox* power1; + TGeoBBox* power2; + + TGeoVolume* power1_vol; + TGeoVolume* power2_vol; + + TGeoTranslation* power1_trans; + TGeoTranslation* power2_trans; + + const Int_t kColor = kBlue; // bus bar color + + TGeoMedium* powerBusVolMed = gGeoMan->GetMedium(PowerBusVolumeMedium); + + // // powerbus - horizontal short + // power1 = new TGeoBBox("power1", (DetectorSizeX[1] - DetectorSizeX[0] - powerbar_width)/2., powerbar_width /2., powerbar_thickness /2.); + // power1_vol = new TGeoVolume("powerbus1", power1, powerBusVolMed); + // power1_vol->SetLineColor(kColor); + // + // // translations + // power1_trans = new TGeoTranslation("", 1 * (DetectorSizeX[1] - DetectorSizeY[0]/2.), 1.5 * DetectorSizeY[1], 0.); + // power_1->AddNode(power1_vol, 1, power1_trans); + // + // power1_trans = new TGeoTranslation("", -1 * (DetectorSizeX[1] - DetectorSizeY[0]/2.), -1.5 * DetectorSizeY[1], 0.); + // power_1->AddNode(power1_vol, 2, power1_trans); + // + // // powerbus - horizontal long + // power1 = new TGeoBBox("power1", (DetectorSizeX[0] - powerbar_width)/2., powerbar_width /2., powerbar_thickness /2.); + // power1_vol = new TGeoVolume("powerbus1", power1, powerBusVolMed); + // power1_vol->SetLineColor(kColor); + // + // // translations + // power1_trans = new TGeoTranslation("", -1 * DetectorSizeX[0], 1.5 * DetectorSizeY[1], 0.); + // power_1->AddNode(power1_vol, 3, power1_trans); + // + // power1_trans = new TGeoTranslation("", 1 * DetectorSizeX[0], -1.5 * DetectorSizeY[1], 0.); + // power_1->AddNode(power1_vol, 4, power1_trans); + + + // powerbus - vertical long + power2 = + new TGeoBBox("power2", powerbar_width / 2., (9 * DetectorSizeY[0] + powerbar_width) / 2., powerbar_thickness / 2.); + power2_vol = new TGeoVolume("powerbus2", power2, powerBusVolMed); + power2_vol->SetLineColor(kColor); + + // translations + power2_trans = new TGeoTranslation("", -(2.0 * DetectorSizeX[0] + 1.0 * DetectorSizeX[1]), 0., 0.); + power_1->AddNode(power2_vol, 1, power2_trans); + power2_trans = new TGeoTranslation("", 2.0 * DetectorSizeX[0] + 1.0 * DetectorSizeX[1], 0., 0.); + power_1->AddNode(power2_vol, 2, power2_trans); + + power2_trans = new TGeoTranslation("", -1.0 * DetectorSizeX[0], 0., 0.); + power_1->AddNode(power2_vol, 3, power2_trans); + power2_trans = new TGeoTranslation("", 1.0 * DetectorSizeX[0], 0., 0.); + power_1->AddNode(power2_vol, 4, power2_trans); + + // // powerbus - vertical middle + // power2 = new TGeoBBox("power2", powerbar_width /2., (3 * DetectorSizeY[1] + powerbar_width) /2., powerbar_thickness /2.); + // power2_vol = new TGeoVolume("powerbus2", power2, powerBusVolMed); + // power2_vol->SetLineColor(kColor); + // + // // translations + // power2_trans = new TGeoTranslation("", -1.5 * DetectorSizeX[0], 0., 0.); + // power_1->AddNode(power2_vol, 7, power2_trans); + // power2_trans = new TGeoTranslation("", 1.5 * DetectorSizeX[0], 0., 0.); + // power_1->AddNode(power2_vol, 8, power2_trans); + // + // // powerbus - vertical short 1 + // power2 = new TGeoBBox("power2", powerbar_width /2., 1 * DetectorSizeY[1] /2., powerbar_thickness /2.); + // power2_vol = new TGeoVolume("powerbus2", power2, powerBusVolMed); + // power2_vol->SetLineColor(kColor); + // // power2_vol->SetLineColor(kRed); + // + // // translations + // power2_trans = new TGeoTranslation("", -0.5 * DetectorSizeX[1], (2.0 * DetectorSizeY[1] + powerbar_width/2.), 0.); + // power_1->AddNode(power2_vol, 9, power2_trans); + // power2_trans = new TGeoTranslation("", 0.5 * DetectorSizeX[1], -(2.0 * DetectorSizeY[1] + powerbar_width/2.), 0.); + // power_1->AddNode(power2_vol,10, power2_trans); + // + // // powerbus - vertical short 2 + // power2 = new TGeoBBox("power2", powerbar_width /2., (1 * DetectorSizeY[1] + powerbar_width) /2., powerbar_thickness /2.); + // power2_vol = new TGeoVolume("powerbus2", power2, powerBusVolMed); + // power2_vol->SetLineColor(kColor); + // + // // translations + // power2_trans = new TGeoTranslation("", -0.5 * DetectorSizeX[1], -2.0 * DetectorSizeY[1], 0.); + // power_1->AddNode(power2_vol,11, power2_trans); + // power2_trans = new TGeoTranslation("", 0.5 * DetectorSizeX[1], 2.0 * DetectorSizeY[1], 0.); + // power_1->AddNode(power2_vol,12, power2_trans); + // + // // powerbus - vertical short 3 + // power2 = new TGeoBBox("power2", powerbar_width /2., (2 * DetectorSizeY[0] + powerbar_width/2.) /2., powerbar_thickness /2.); + // power2_vol = new TGeoVolume("powerbus2", power2, powerBusVolMed); + // power2_vol->SetLineColor(kColor); + // + // // translations + // power2_trans = new TGeoTranslation("", -0.5 * DetectorSizeX[0], (1.5 * DetectorSizeY[0] + powerbar_width/4.), 0.); + // power_1->AddNode(power2_vol,11, power2_trans); + // power2_trans = new TGeoTranslation("", 0.5 * DetectorSizeX[0], -(1.5 * DetectorSizeY[0] + powerbar_width/4.), 0.); + // power_1->AddNode(power2_vol,12, power2_trans); + + Int_t l; + for (l = 0; l < 4; l++) + if ((ShowLayer[l]) && (BusBarOrientation[l] == 1)) // if geometry contains layer l + { + TString layername = Form("layer%02d", l + 1); + TGeoTranslation* power_placement = + new TGeoTranslation(0, 0, LayerPosition[l] + LayerThickness / 2. + powerbar_position); + gGeoMan->GetVolume(layername)->AddNode(power_1, l, power_placement); + } +} + + +void create_power_bars_horizontal() +{ + const TString power_01 = "power_bars_trd1"; + TGeoVolume* power_1 = new TGeoVolumeAssembly(power_01); + + TGeoBBox* power1; + TGeoBBox* power2; + + TGeoVolume* power1_vol; + TGeoVolume* power2_vol; + + TGeoTranslation* power1_trans; + TGeoTranslation* power2_trans; + + const Int_t kColor = kBlue; // bus bar color + + TGeoMedium* powerBusVolMed = gGeoMan->GetMedium(PowerBusVolumeMedium); + + // powerbus - vertical short + power1 = new TGeoBBox("power1", powerbar_width / 2., (DetectorSizeY[1] - DetectorSizeY[0] - powerbar_width) / 2., + powerbar_thickness / 2.); + power1_vol = new TGeoVolume("powerbus1", power1, powerBusVolMed); + power1_vol->SetLineColor(kColor); + + // translations + power1_trans = new TGeoTranslation("", 1.5 * DetectorSizeX[1], -1 * (DetectorSizeY[1] - DetectorSizeY[0] / 2.), 0.); + power_1->AddNode(power1_vol, 1, power1_trans); + + power1_trans = new TGeoTranslation("", -1.5 * DetectorSizeX[1], 1 * (DetectorSizeY[1] - DetectorSizeY[0] / 2.), 0.); + power_1->AddNode(power1_vol, 2, power1_trans); + + // powerbus - vertical long + power1 = + new TGeoBBox("power1", powerbar_width / 2., (DetectorSizeY[0] - powerbar_width) / 2., powerbar_thickness / 2.); + power1_vol = new TGeoVolume("powerbus1", power1, powerBusVolMed); + power1_vol->SetLineColor(kColor); + + // translations + power1_trans = new TGeoTranslation("", 1.5 * DetectorSizeX[1], 1 * DetectorSizeY[0], 0.); + power_1->AddNode(power1_vol, 3, power1_trans); + + power1_trans = new TGeoTranslation("", -1.5 * DetectorSizeX[1], -1 * DetectorSizeY[0], 0.); + power_1->AddNode(power1_vol, 4, power1_trans); + + + // powerbus - horizontal long + power2 = + new TGeoBBox("power2", (7 * DetectorSizeX[1] + powerbar_width) / 2., powerbar_width / 2., powerbar_thickness / 2.); + power2_vol = new TGeoVolume("powerbus2", power2, powerBusVolMed); + power2_vol->SetLineColor(kColor); + + // translations + power2_trans = new TGeoTranslation("", 0., -2.5 * DetectorSizeY[1], 0.); + power_1->AddNode(power2_vol, 1, power2_trans); + power2_trans = new TGeoTranslation("", 0., 2.5 * DetectorSizeY[1], 0.); + power_1->AddNode(power2_vol, 2, power2_trans); + + power2_trans = new TGeoTranslation("", 0., -1.5 * DetectorSizeY[1], 0.); + power_1->AddNode(power2_vol, 3, power2_trans); + power2_trans = new TGeoTranslation("", 0., 1.5 * DetectorSizeY[1], 0.); + power_1->AddNode(power2_vol, 4, power2_trans); + + // powerbus - horizontal middle + power2 = + new TGeoBBox("power2", (3 * DetectorSizeX[1] + powerbar_width) / 2., powerbar_width / 2., powerbar_thickness / 2.); + power2_vol = new TGeoVolume("powerbus2", power2, powerBusVolMed); + power2_vol->SetLineColor(kColor); + + // translations + power2_trans = new TGeoTranslation("", 0., -1.5 * DetectorSizeY[0], 0.); + power_1->AddNode(power2_vol, 7, power2_trans); + power2_trans = new TGeoTranslation("", 0., 1.5 * DetectorSizeY[0], 0.); + power_1->AddNode(power2_vol, 8, power2_trans); + + // powerbus - horizontal short 1 + power2 = new TGeoBBox("power2", 2 * DetectorSizeX[1] / 2., powerbar_width / 2., powerbar_thickness / 2.); + power2_vol = new TGeoVolume("powerbus2", power2, powerBusVolMed); + power2_vol->SetLineColor(kColor); + // power2_vol->SetLineColor(kRed); + + // translations + power2_trans = new TGeoTranslation("", (2.5 * DetectorSizeX[1] + powerbar_width / 2.), 0.5 * DetectorSizeY[1], 0.); + power_1->AddNode(power2_vol, 9, power2_trans); + power2_trans = new TGeoTranslation("", -(2.5 * DetectorSizeX[1] + powerbar_width / 2.), -0.5 * DetectorSizeY[1], 0.); + power_1->AddNode(power2_vol, 10, power2_trans); + + // powerbus - horizontal short 2 + power2 = + new TGeoBBox("power2", (2 * DetectorSizeX[1] + powerbar_width) / 2., powerbar_width / 2., powerbar_thickness / 2.); + power2_vol = new TGeoVolume("powerbus2", power2, powerBusVolMed); + power2_vol->SetLineColor(kColor); + + // translations + power2_trans = new TGeoTranslation("", -2.5 * DetectorSizeX[1], 0.5 * DetectorSizeY[1], 0.); + power_1->AddNode(power2_vol, 11, power2_trans); + power2_trans = new TGeoTranslation("", 2.5 * DetectorSizeX[1], -0.5 * DetectorSizeY[1], 0.); + power_1->AddNode(power2_vol, 12, power2_trans); + + // powerbus - horizontal short 3 + power2 = new TGeoBBox("power2", (2 * DetectorSizeX[0] + powerbar_width / 2.) / 2., powerbar_width / 2., + powerbar_thickness / 2.); + power2_vol = new TGeoVolume("powerbus2", power2, powerBusVolMed); + power2_vol->SetLineColor(kColor); + + // translations + power2_trans = new TGeoTranslation("", (1.5 * DetectorSizeX[0] + powerbar_width / 4.), 0.5 * DetectorSizeY[0], 0.); + power_1->AddNode(power2_vol, 11, power2_trans); + power2_trans = new TGeoTranslation("", -(1.5 * DetectorSizeX[0] + powerbar_width / 4.), -0.5 * DetectorSizeY[0], 0.); + power_1->AddNode(power2_vol, 12, power2_trans); + + Int_t l; + for (l = 0; l < 4; l++) + if ((ShowLayer[l]) && (BusBarOrientation[l] == 0)) // if geometry contains layer l + { + TString layername = Form("layer%02d", l + 1); + TGeoTranslation* power_placement = + new TGeoTranslation(0, 0, LayerPosition[l] + LayerThickness / 2. + powerbar_position); + gGeoMan->GetVolume(layername)->AddNode(power_1, l, power_placement); + } +} + + +void create_xtru_supports() +{ + const TString trd_01 = "support_trd1"; + TGeoVolume* trd_1 = new TGeoVolumeAssembly(trd_01); + + const TString trd_02 = "support_trd2"; + TGeoVolume* trd_2 = new TGeoVolumeAssembly(trd_02); + + const TString trd_03 = "support_trd3"; + TGeoVolume* trd_3 = new TGeoVolumeAssembly(trd_03); + + // const TString trdSupport = "supportframe"; + // TGeoVolume* trdsupport = new TGeoVolumeAssembly(trdSupport); + // + // trdsupport->AddNode(trd_1, 1); + // trdsupport->AddNode(trd_2, 2); + // trdsupport->AddNode(trd_3, 3); + + TGeoMedium* aluminiumVolMed = gGeoMan->GetMedium(AluminiumVolumeMedium); // define Volume Medium + + const Double_t x[12] = {-15, -15, -1, -1, -15, -15, 15, 15, 1, 1, 15, 15}; // IPB 400 + const Double_t y[12] = {-20, -18, -18, 18, 18, 20, + 20, 18, 18, -18, -18, -20}; // 30 x 40 cm in size, 2 cm wall thickness + const Double_t Hwid = -2 * x[0]; // 30 + const Double_t Hhei = -2 * y[0]; // 40 + + Double_t AperX[3] = {450., 550., 600.}; // inner aperture in X of support structure for stations 1,2,3 + Double_t AperY[3] = {350., 450., 500.}; // inner aperture in Y of support structure for stations 1,2,3 + Double_t PilPosX; + Double_t BarPosY; + + const Double_t BeamHeight = 570; // beamline is at 5.7m above floor + + Double_t PilPosZ[6]; // PilPosZ + // PilPosZ[0] = LayerPosition[0] + LayerThickness/2.; + // PilPosZ[1] = LayerPosition[3] + LayerThickness/2.; + // PilPosZ[2] = LayerPosition[4] + LayerThickness/2.; + // PilPosZ[3] = LayerPosition[7] + LayerThickness/2.; + // PilPosZ[4] = LayerPosition[8] + LayerThickness/2.; + // PilPosZ[5] = LayerPosition[9] + LayerThickness/2.; + + PilPosZ[0] = LayerPosition[0] + 15; + PilPosZ[1] = LayerPosition[3] - 15 + LayerThickness; + PilPosZ[2] = LayerPosition[4] + 15; + PilPosZ[3] = LayerPosition[7] - 15 + LayerThickness; + PilPosZ[4] = LayerPosition[8] + 15; + PilPosZ[5] = LayerPosition[9] - 15 + LayerThickness; + + // cout << "PilPosZ[0]: " << PilPosZ[0] << endl; + // cout << "PilPosZ[1]: " << PilPosZ[1] << endl; + + TGeoRotation* rotx090 = new TGeoRotation("rotx090"); + rotx090->RotateX(90.); // rotate 90 deg around x-axis + TGeoRotation* roty090 = new TGeoRotation("roty090"); + roty090->RotateY(90.); // rotate 90 deg around y-axis + TGeoRotation* rotz090 = new TGeoRotation("rotz090"); + rotz090->RotateZ(90.); // rotate 90 deg around y-axis + TGeoRotation* roty270 = new TGeoRotation("roty270"); + roty270->RotateY(270.); // rotate 270 deg around y-axis + + TGeoRotation* rotzx01 = new TGeoRotation("rotzx01"); + rotzx01->RotateZ(90.); // rotate 90 deg around z-axis + rotzx01->RotateX(90.); // rotate 90 deg around x-axis + + // TGeoRotation *rotxz01 = new TGeoRotation("rotxz01"); + // rotxz01->RotateX( 90.); // rotate 90 deg around x-axis + // rotxz01->RotateZ( 90.); // rotate 90 deg around z-axis + + Double_t ang1 = atan(3. / 4.) * 180. / acos(-1.); + // cout << "DEDE " << ang1 << endl; + // Double_t sin1 = acos(-1.); + // cout << "DEDE " << sin1 << endl; + TGeoRotation* rotx080 = new TGeoRotation("rotx080"); + rotx080->RotateX(90. - ang1); // rotate 80 deg around x-axis + TGeoRotation* rotx100 = new TGeoRotation("rotx100"); + rotx100->RotateX(90. + ang1); // rotate 100 deg around x-axis + + TGeoRotation* rotxy01 = new TGeoRotation("rotxy01"); + rotxy01->RotateX(90.); // rotate 90 deg around x-axis + rotxy01->RotateZ(-ang1); // rotate ang1 around rotated y-axis + + TGeoRotation* rotxy02 = new TGeoRotation("rotxy02"); + rotxy02->RotateX(90.); // rotate 90 deg around x-axis + rotxy02->RotateZ(ang1); // rotate ang1 around rotated y-axis + + + //------------------- + // vertical pillars (Y) + //------------------- + + // station 1 + if (ShowLayer[0]) // if geometry contains layer 1 (1st layer of station 1) + { + TGeoXtru* trd_H_vert1 = new TGeoXtru(2); // define Xtrusion of 2 planes + trd_H_vert1->DefinePolygon(12, x, y); + trd_H_vert1->DefineSection(0, -(AperY[0] + Hhei), 0, 0, 1.0); + trd_H_vert1->DefineSection(1, BeamHeight, 0, 0, 1.0); + TGeoVolume* trd_H_vert_vol1 = new TGeoVolume("trd_H_y_01", trd_H_vert1, aluminiumVolMed); + trd_H_vert_vol1->SetLineColor(kYellow); + PilPosX = AperX[0]; + + TGeoCombiTrans* trd_H_vert_combi01 = new TGeoCombiTrans((PilPosX + Hhei / 2.), 0., PilPosZ[0], rotzx01); + trd_1->AddNode(trd_H_vert_vol1, 11, trd_H_vert_combi01); + TGeoCombiTrans* trd_H_vert_combi02 = new TGeoCombiTrans(-(PilPosX + Hhei / 2.), 0., PilPosZ[0], rotzx01); + trd_1->AddNode(trd_H_vert_vol1, 12, trd_H_vert_combi02); + TGeoCombiTrans* trd_H_vert_combi03 = new TGeoCombiTrans((PilPosX + Hhei / 2.), 0., PilPosZ[1], rotzx01); + trd_1->AddNode(trd_H_vert_vol1, 13, trd_H_vert_combi03); + TGeoCombiTrans* trd_H_vert_combi04 = new TGeoCombiTrans(-(PilPosX + Hhei / 2.), 0., PilPosZ[1], rotzx01); + trd_1->AddNode(trd_H_vert_vol1, 14, trd_H_vert_combi04); + } + + // station 2 + if (ShowLayer[4]) // if geometry contains layer 5 (1st layer of station 2) + { + TGeoXtru* trd_H_vert1 = new TGeoXtru(2); // define Xtrusion of 2 planes + trd_H_vert1->DefinePolygon(12, x, y); + trd_H_vert1->DefineSection(0, -(AperY[1] + Hhei), 0, 0, 1.0); + trd_H_vert1->DefineSection(1, BeamHeight, 0, 0, 1.0); + TGeoVolume* trd_H_vert_vol1 = new TGeoVolume("trd_H_y_02", trd_H_vert1, aluminiumVolMed); + trd_H_vert_vol1->SetLineColor(kYellow); + PilPosX = AperX[1]; + + TGeoCombiTrans* trd_H_vert_combi01 = new TGeoCombiTrans((PilPosX + Hhei / 2.), 0., PilPosZ[2], rotzx01); + trd_2->AddNode(trd_H_vert_vol1, 21, trd_H_vert_combi01); + TGeoCombiTrans* trd_H_vert_combi02 = new TGeoCombiTrans(-(PilPosX + Hhei / 2.), 0., PilPosZ[2], rotzx01); + trd_2->AddNode(trd_H_vert_vol1, 22, trd_H_vert_combi02); + TGeoCombiTrans* trd_H_vert_combi03 = new TGeoCombiTrans((PilPosX + Hhei / 2.), 0., PilPosZ[3], rotzx01); + trd_2->AddNode(trd_H_vert_vol1, 23, trd_H_vert_combi03); + TGeoCombiTrans* trd_H_vert_combi04 = new TGeoCombiTrans(-(PilPosX + Hhei / 2.), 0., PilPosZ[3], rotzx01); + trd_2->AddNode(trd_H_vert_vol1, 24, trd_H_vert_combi04); + } + + // station 3 + if (ShowLayer[8]) // if geometry contains layer 9 (1st layer of station 3) + { + TGeoXtru* trd_H_vert1 = new TGeoXtru(2); // define Xtrusion of 2 planes + trd_H_vert1->DefinePolygon(12, x, y); + trd_H_vert1->DefineSection(0, -(AperY[2] + Hhei), 0, 0, 1.0); + trd_H_vert1->DefineSection(1, BeamHeight, 0, 0, 1.0); + TGeoVolume* trd_H_vert_vol1 = new TGeoVolume("trd_H_y_03", trd_H_vert1, aluminiumVolMed); + trd_H_vert_vol1->SetLineColor(kYellow); + PilPosX = AperX[2]; + + TGeoCombiTrans* trd_H_vert_combi01 = new TGeoCombiTrans((PilPosX + Hhei / 2.), 0., PilPosZ[4], rotzx01); + trd_3->AddNode(trd_H_vert_vol1, 31, trd_H_vert_combi01); + TGeoCombiTrans* trd_H_vert_combi02 = new TGeoCombiTrans(-(PilPosX + Hhei / 2.), 0., PilPosZ[4], rotzx01); + trd_3->AddNode(trd_H_vert_vol1, 32, trd_H_vert_combi02); + TGeoCombiTrans* trd_H_vert_combi03 = new TGeoCombiTrans((PilPosX + Hhei / 2.), 0., PilPosZ[5], rotzx01); + trd_3->AddNode(trd_H_vert_vol1, 33, trd_H_vert_combi03); + TGeoCombiTrans* trd_H_vert_combi04 = new TGeoCombiTrans(-(PilPosX + Hhei / 2.), 0., PilPosZ[5], rotzx01); + trd_3->AddNode(trd_H_vert_vol1, 34, trd_H_vert_combi04); + } + + + //------------------- + // horizontal supports (X) + //------------------- + + // station 1 + if (ShowLayer[0]) // if geometry contains layer 1 (1st layer of station 1) + { + TGeoXtru* trd_H_hori1 = new TGeoXtru(2); // define Xtrusion of 2 planes + trd_H_hori1->DefinePolygon(12, x, y); + trd_H_hori1->DefineSection(0, -AperX[0], 0, 0, 1.0); + trd_H_hori1->DefineSection(1, AperX[0], 0, 0, 1.0); + TGeoVolume* trd_H_hori_vol1 = new TGeoVolume("trd_H_x_01", trd_H_hori1, aluminiumVolMed); + trd_H_hori_vol1->SetLineColor(kRed); + BarPosY = AperY[0]; + + TGeoCombiTrans* trd_H_hori_combi01 = new TGeoCombiTrans(0., (BarPosY + Hhei / 2.), PilPosZ[0], roty090); + trd_1->AddNode(trd_H_hori_vol1, 11, trd_H_hori_combi01); + TGeoCombiTrans* trd_H_hori_combi02 = new TGeoCombiTrans(0., -(BarPosY + Hhei / 2.), PilPosZ[0], roty090); + trd_1->AddNode(trd_H_hori_vol1, 12, trd_H_hori_combi02); + TGeoCombiTrans* trd_H_hori_combi03 = new TGeoCombiTrans(0., (BarPosY + Hhei / 2.), PilPosZ[1], roty090); + trd_1->AddNode(trd_H_hori_vol1, 13, trd_H_hori_combi03); + TGeoCombiTrans* trd_H_hori_combi04 = new TGeoCombiTrans(0., -(BarPosY + Hhei / 2.), PilPosZ[1], roty090); + trd_1->AddNode(trd_H_hori_vol1, 14, trd_H_hori_combi04); + } + + // station 2 + if (ShowLayer[4]) // if geometry contains layer 5 (1st layer of station 2) + { + TGeoXtru* trd_H_hori1 = new TGeoXtru(2); // define Xtrusion of 2 planes + trd_H_hori1->DefinePolygon(12, x, y); + trd_H_hori1->DefineSection(0, -AperX[1], 0, 0, 1.0); + trd_H_hori1->DefineSection(1, AperX[1], 0, 0, 1.0); + TGeoVolume* trd_H_hori_vol1 = new TGeoVolume("trd_H_x_02", trd_H_hori1, aluminiumVolMed); + trd_H_hori_vol1->SetLineColor(kRed); + BarPosY = AperY[1]; + + TGeoCombiTrans* trd_H_hori_combi01 = new TGeoCombiTrans(0., (BarPosY + Hhei / 2.), PilPosZ[2], roty090); + trd_2->AddNode(trd_H_hori_vol1, 21, trd_H_hori_combi01); + TGeoCombiTrans* trd_H_hori_combi02 = new TGeoCombiTrans(0., -(BarPosY + Hhei / 2.), PilPosZ[2], roty090); + trd_2->AddNode(trd_H_hori_vol1, 22, trd_H_hori_combi02); + TGeoCombiTrans* trd_H_hori_combi03 = new TGeoCombiTrans(0., (BarPosY + Hhei / 2.), PilPosZ[3], roty090); + trd_2->AddNode(trd_H_hori_vol1, 23, trd_H_hori_combi03); + TGeoCombiTrans* trd_H_hori_combi04 = new TGeoCombiTrans(0., -(BarPosY + Hhei / 2.), PilPosZ[3], roty090); + trd_2->AddNode(trd_H_hori_vol1, 24, trd_H_hori_combi04); + } + + // station 3 + if (ShowLayer[8]) // if geometry contains layer 9 (1st layer of station 3) + { + TGeoXtru* trd_H_hori1 = new TGeoXtru(2); // define Xtrusion of 2 planes + trd_H_hori1->DefinePolygon(12, x, y); + trd_H_hori1->DefineSection(0, -AperX[2], 0, 0, 1.0); + trd_H_hori1->DefineSection(1, AperX[2], 0, 0, 1.0); + TGeoVolume* trd_H_hori_vol1 = new TGeoVolume("trd_H_x_03", trd_H_hori1, aluminiumVolMed); + trd_H_hori_vol1->SetLineColor(kRed); + BarPosY = AperY[2]; + + TGeoCombiTrans* trd_H_hori_combi01 = new TGeoCombiTrans(0., (BarPosY + Hhei / 2.), PilPosZ[4], roty090); + trd_3->AddNode(trd_H_hori_vol1, 31, trd_H_hori_combi01); + TGeoCombiTrans* trd_H_hori_combi02 = new TGeoCombiTrans(0., -(BarPosY + Hhei / 2.), PilPosZ[4], roty090); + trd_3->AddNode(trd_H_hori_vol1, 32, trd_H_hori_combi02); + TGeoCombiTrans* trd_H_hori_combi03 = new TGeoCombiTrans(0., (BarPosY + Hhei / 2.), PilPosZ[5], roty090); + trd_3->AddNode(trd_H_hori_vol1, 33, trd_H_hori_combi03); + TGeoCombiTrans* trd_H_hori_combi04 = new TGeoCombiTrans(0., -(BarPosY + Hhei / 2.), PilPosZ[5], roty090); + trd_3->AddNode(trd_H_hori_vol1, 34, trd_H_hori_combi04); + } + + + //------------------- + // horizontal supports (Z) + //------------------- + + // station 1 + if (ShowLayer[0]) // if geometry contains layer 1 (1st layer of station 1) + { + TGeoXtru* trd_H_slope1 = new TGeoXtru(2); // define Xtrusion of 2 planes + trd_H_slope1->DefinePolygon(12, x, y); + trd_H_slope1->DefineSection(0, -(PilPosZ[1] - PilPosZ[0] - Hwid) / 2., 0, 0, 1.0); + trd_H_slope1->DefineSection(1, +(PilPosZ[1] - PilPosZ[0] - Hwid) / 2., 0, 0, 1.0); + TGeoVolume* trd_H_slope_vol1 = new TGeoVolume("trd_H_z_01", trd_H_slope1, aluminiumVolMed); + trd_H_slope_vol1->SetLineColor(kGreen); + PilPosX = AperX[0]; + BarPosY = AperY[0]; + + TGeoCombiTrans* trd_H_slope_combi01 = + new TGeoCombiTrans((PilPosX + Hhei / 2.), (BarPosY + Hhei - Hwid / 2.), (PilPosZ[0] + PilPosZ[1]) / 2., rotz090); + trd_1->AddNode(trd_H_slope_vol1, 11, trd_H_slope_combi01); + TGeoCombiTrans* trd_H_slope_combi02 = + new TGeoCombiTrans(-(PilPosX + Hhei / 2.), (BarPosY + Hhei - Hwid / 2.), (PilPosZ[0] + PilPosZ[1]) / 2., rotz090); + trd_1->AddNode(trd_H_slope_vol1, 12, trd_H_slope_combi02); + TGeoCombiTrans* trd_H_slope_combi03 = + new TGeoCombiTrans((PilPosX + Hhei / 2.), -(BarPosY + Hhei - Hwid / 2.), (PilPosZ[0] + PilPosZ[1]) / 2., rotz090); + trd_1->AddNode(trd_H_slope_vol1, 13, trd_H_slope_combi03); + TGeoCombiTrans* trd_H_slope_combi04 = new TGeoCombiTrans(-(PilPosX + Hhei / 2.), -(BarPosY + Hhei - Hwid / 2.), + (PilPosZ[0] + PilPosZ[1]) / 2., rotz090); + trd_1->AddNode(trd_H_slope_vol1, 14, trd_H_slope_combi04); + } + + // station 2 + if (ShowLayer[4]) // if geometry contains layer 5 (1st layer of station 2) + { + TGeoXtru* trd_H_slope1 = new TGeoXtru(2); // define Xtrusion of 2 planes + trd_H_slope1->DefinePolygon(12, x, y); + trd_H_slope1->DefineSection(0, -(PilPosZ[3] - PilPosZ[2] - Hwid) / 2., 0, 0, 1.0); + trd_H_slope1->DefineSection(1, +(PilPosZ[3] - PilPosZ[2] - Hwid) / 2., 0, 0, 1.0); + TGeoVolume* trd_H_slope_vol1 = new TGeoVolume("trd_H_z_02", trd_H_slope1, aluminiumVolMed); + trd_H_slope_vol1->SetLineColor(kGreen); + PilPosX = AperX[1]; + BarPosY = AperY[1]; + + TGeoCombiTrans* trd_H_slope_combi01 = + new TGeoCombiTrans((PilPosX + Hhei / 2.), (BarPosY + Hhei - Hwid / 2.), (PilPosZ[2] + PilPosZ[3]) / 2., rotz090); + trd_2->AddNode(trd_H_slope_vol1, 21, trd_H_slope_combi01); + TGeoCombiTrans* trd_H_slope_combi02 = + new TGeoCombiTrans(-(PilPosX + Hhei / 2.), (BarPosY + Hhei - Hwid / 2.), (PilPosZ[2] + PilPosZ[3]) / 2., rotz090); + trd_2->AddNode(trd_H_slope_vol1, 22, trd_H_slope_combi02); + TGeoCombiTrans* trd_H_slope_combi03 = + new TGeoCombiTrans((PilPosX + Hhei / 2.), -(BarPosY + Hhei - Hwid / 2.), (PilPosZ[2] + PilPosZ[3]) / 2., rotz090); + trd_2->AddNode(trd_H_slope_vol1, 23, trd_H_slope_combi03); + TGeoCombiTrans* trd_H_slope_combi04 = new TGeoCombiTrans(-(PilPosX + Hhei / 2.), -(BarPosY + Hhei - Hwid / 2.), + (PilPosZ[2] + PilPosZ[3]) / 2., rotz090); + trd_2->AddNode(trd_H_slope_vol1, 24, trd_H_slope_combi04); + } + + // station 3 + if (ShowLayer[8]) // if geometry contains layer 9 (1st layer of station 3) + { + TGeoXtru* trd_H_slope1 = new TGeoXtru(2); // define Xtrusion of 2 planes + trd_H_slope1->DefinePolygon(12, x, y); + trd_H_slope1->DefineSection(0, -(PilPosZ[5] - PilPosZ[4] - Hwid) / 2., 0, 0, 1.0); + trd_H_slope1->DefineSection(1, +(PilPosZ[5] - PilPosZ[4] - Hwid) / 2., 0, 0, 1.0); + TGeoVolume* trd_H_slope_vol1 = new TGeoVolume("trd_H_z_03", trd_H_slope1, aluminiumVolMed); + trd_H_slope_vol1->SetLineColor(kGreen); + PilPosX = AperX[2]; + BarPosY = AperY[2]; + + TGeoCombiTrans* trd_H_slope_combi01 = + new TGeoCombiTrans((PilPosX + Hhei / 2.), (BarPosY + Hhei - Hwid / 2.), (PilPosZ[4] + PilPosZ[5]) / 2., rotz090); + trd_3->AddNode(trd_H_slope_vol1, 31, trd_H_slope_combi01); + TGeoCombiTrans* trd_H_slope_combi02 = + new TGeoCombiTrans(-(PilPosX + Hhei / 2.), (BarPosY + Hhei - Hwid / 2.), (PilPosZ[4] + PilPosZ[5]) / 2., rotz090); + trd_3->AddNode(trd_H_slope_vol1, 32, trd_H_slope_combi02); + TGeoCombiTrans* trd_H_slope_combi03 = + new TGeoCombiTrans((PilPosX + Hhei / 2.), -(BarPosY + Hhei - Hwid / 2.), (PilPosZ[4] + PilPosZ[5]) / 2., rotz090); + trd_3->AddNode(trd_H_slope_vol1, 33, trd_H_slope_combi03); + TGeoCombiTrans* trd_H_slope_combi04 = new TGeoCombiTrans(-(PilPosX + Hhei / 2.), -(BarPosY + Hhei - Hwid / 2.), + (PilPosZ[4] + PilPosZ[5]) / 2., rotz090); + trd_3->AddNode(trd_H_slope_vol1, 34, trd_H_slope_combi04); + } + + if (IncludeLabels) { + + Int_t text_height = 40; + Int_t text_thickness = 8; + + TGeoTranslation* tr200 = + new TGeoTranslation(0., (AperY[0] + Hhei + text_height / 2.), PilPosZ[0] - 15 + text_thickness / 2.); + TGeoTranslation* tr201 = + new TGeoTranslation(0., (AperY[1] + Hhei + text_height / 2.), PilPosZ[2] - 15 + text_thickness / 2.); + TGeoTranslation* tr202 = + new TGeoTranslation(0., (AperY[2] + Hhei + text_height / 2.), PilPosZ[4] - 15 + text_thickness / 2.); + + TGeoCombiTrans* tr203 = + new TGeoCombiTrans(-(AperX[0] + Hhei + text_thickness / 2.), (AperY[0] + Hhei - Hwid - text_height / 2.), + (PilPosZ[0] + PilPosZ[1]) / 2., roty090); + TGeoCombiTrans* tr204 = + new TGeoCombiTrans(-(AperX[1] + Hhei + text_thickness / 2.), (AperY[1] + Hhei - Hwid - text_height / 2.), + (PilPosZ[2] + PilPosZ[3]) / 2., roty090); + TGeoCombiTrans* tr205 = + new TGeoCombiTrans(-(AperX[2] + Hhei + text_thickness / 2.), (AperY[2] + Hhei - Hwid - text_height / 2.), + (PilPosZ[4] + PilPosZ[5]) / 2., roty090); + TGeoCombiTrans* tr206 = + new TGeoCombiTrans((AperX[0] + Hhei + text_thickness / 2.), (AperY[0] + Hhei - Hwid - text_height / 2.), + (PilPosZ[0] + PilPosZ[1]) / 2., roty270); + TGeoCombiTrans* tr207 = + new TGeoCombiTrans((AperX[1] + Hhei + text_thickness / 2.), (AperY[1] + Hhei - Hwid - text_height / 2.), + (PilPosZ[2] + PilPosZ[3]) / 2., roty270); + TGeoCombiTrans* tr208 = + new TGeoCombiTrans((AperX[2] + Hhei + text_thickness / 2.), (AperY[2] + Hhei - Hwid - text_height / 2.), + (PilPosZ[4] + PilPosZ[5]) / 2., roty270); + + TGeoVolume* trdbox1 = new TGeoVolumeAssembly("trdbox1"); // volume for TRD text (108, 40, 8) + TGeoVolume* trdbox2 = new TGeoVolumeAssembly("trdbox2"); // volume for TRD text (108, 40, 8) + TGeoVolume* trdbox3 = new TGeoVolumeAssembly("trdbox3"); // volume for TRD text (108, 40, 8) + add_trd_labels(trdbox1, trdbox2, trdbox3); + + // final placement + if (ShowLayer[0]) // if geometry contains layer 1 (1st layer of station 1) + { + // trd_1->AddNode(trdbox1, 1, tr200); + trd_1->AddNode(trdbox1, 4, tr203); + trd_1->AddNode(trdbox1, 7, tr206); + } + if (ShowLayer[4]) // if geometry contains layer 5 (1st layer of station 2) + { + // trd_2->AddNode(trdbox2, 2, tr201); + trd_2->AddNode(trdbox2, 5, tr204); + trd_2->AddNode(trdbox2, 8, tr207); + } + if (ShowLayer[8]) // if geometry contains layer 9 (1st layer of station 3) + { + // trd_3->AddNode(trdbox3, 3, tr202); + trd_3->AddNode(trdbox3, 6, tr205); + trd_3->AddNode(trdbox3, 9, tr208); + } + } + + // gGeoMan->GetVolume(geoVersion)->AddNode(trdsupport,1); + + if (ShowLayer[0]) // if geometry contains layer 1 (1st layer of station 1) + gGeoMan->GetVolume(geoVersion)->AddNode(trd_1, 1); + if (ShowLayer[4]) // if geometry contains layer 5 (1st layer of station 2) + gGeoMan->GetVolume(geoVersion)->AddNode(trd_2, 2); + if (ShowLayer[8]) // if geometry contains layer 9 (1st layer of station 3) + gGeoMan->GetVolume(geoVersion)->AddNode(trd_3, 3); +} + + +void add_trd_labels(TGeoVolume* trdbox1, TGeoVolume* trdbox2, TGeoVolume* trdbox3) +{ + // write TRD (the 3 characters) in a simple geometry + TGeoMedium* textVolMed = gGeoMan->GetMedium(TextVolumeMedium); + + Int_t Tcolor = kBlue; // kRed; + Int_t Rcolor = kBlue; // kRed; // kRed; + Int_t Dcolor = kBlue; // kRed; // kYellow; + Int_t Icolor = kBlue; // kRed; + + // define transformations for letter pieces + // T + TGeoTranslation* tr01 = new TGeoTranslation(0., -4., 0.); + TGeoTranslation* tr02 = new TGeoTranslation(0., 16., 0.); + + // R + TGeoTranslation* tr11 = new TGeoTranslation(10, 0., 0.); + TGeoTranslation* tr12 = new TGeoTranslation(2, 0., 0.); + TGeoTranslation* tr13 = new TGeoTranslation(2, 16., 0.); + TGeoTranslation* tr14 = new TGeoTranslation(-2, 8., 0.); + TGeoTranslation* tr15 = new TGeoTranslation(-6, 0., 0.); + + // D + TGeoTranslation* tr21 = new TGeoTranslation(12., 0., 0.); + TGeoTranslation* tr22 = new TGeoTranslation(6., 16., 0.); + TGeoTranslation* tr23 = new TGeoTranslation(6., -16., 0.); + TGeoTranslation* tr24 = new TGeoTranslation(4., 0., 0.); + + // I + TGeoTranslation* tr31 = new TGeoTranslation(0., 0., 0.); + TGeoTranslation* tr32 = new TGeoTranslation(0., 16., 0.); + TGeoTranslation* tr33 = new TGeoTranslation(0., -16., 0.); + + // make letter T + // TGeoVolume *T = geom->MakeBox("T", Vacuum, 25., 25., 5.); + // T->SetVisibility(kFALSE); + TGeoVolume* T = new TGeoVolumeAssembly("Tbox"); // volume for T + + TGeoBBox* Tbar1b = new TGeoBBox("trd_Tbar1b", 4., 16., 4.); // | vertical + TGeoVolume* Tbar1 = new TGeoVolume("Tbar1", Tbar1b, textVolMed); + Tbar1->SetLineColor(Tcolor); + T->AddNode(Tbar1, 1, tr01); + TGeoBBox* Tbar2b = new TGeoBBox("trd_Tbar2b", 16, 4., 4.); // - top + TGeoVolume* Tbar2 = new TGeoVolume("Tbar2", Tbar2b, textVolMed); + Tbar2->SetLineColor(Tcolor); + T->AddNode(Tbar2, 1, tr02); + + // make letter R + // TGeoVolume *R = geom->MakeBox("R", Vacuum, 25., 25., 5.); + // R->SetVisibility(kFALSE); + TGeoVolume* R = new TGeoVolumeAssembly("Rbox"); // volume for R + + TGeoBBox* Rbar1b = new TGeoBBox("trd_Rbar1b", 4., 20, 4.); + TGeoVolume* Rbar1 = new TGeoVolume("Rbar1", Rbar1b, textVolMed); + Rbar1->SetLineColor(Rcolor); + R->AddNode(Rbar1, 1, tr11); + TGeoBBox* Rbar2b = new TGeoBBox("trd_Rbar2b", 4., 4., 4.); + TGeoVolume* Rbar2 = new TGeoVolume("Rbar2", Rbar2b, textVolMed); + Rbar2->SetLineColor(Rcolor); + R->AddNode(Rbar2, 1, tr12); + R->AddNode(Rbar2, 2, tr13); + TGeoTubeSeg* Rtub1b = new TGeoTubeSeg("trd_Rtub1b", 4., 12, 4., 90., 270.); + TGeoVolume* Rtub1 = new TGeoVolume("Rtub1", (TGeoShape*) Rtub1b, textVolMed); + Rtub1->SetLineColor(Rcolor); + R->AddNode(Rtub1, 1, tr14); + TGeoArb8* Rbar3b = new TGeoArb8("trd_Rbar3b", 4.); + TGeoVolume* Rbar3 = new TGeoVolume("Rbar3", Rbar3b, textVolMed); + Rbar3->SetLineColor(Rcolor); + TGeoArb8* arb = (TGeoArb8*) Rbar3->GetShape(); + arb->SetVertex(0, 12., -4.); + arb->SetVertex(1, 0., -20.); + arb->SetVertex(2, -8., -20.); + arb->SetVertex(3, 4., -4.); + arb->SetVertex(4, 12., -4.); + arb->SetVertex(5, 0., -20.); + arb->SetVertex(6, -8., -20.); + arb->SetVertex(7, 4., -4.); + R->AddNode(Rbar3, 1, tr15); + + // make letter D + // TGeoVolume *D = geom->MakeBox("D", Vacuum, 25., 25., 5.); + // D->SetVisibility(kFALSE); + TGeoVolume* D = new TGeoVolumeAssembly("Dbox"); // volume for D + + TGeoBBox* Dbar1b = new TGeoBBox("trd_Dbar1b", 4., 20, 4.); + TGeoVolume* Dbar1 = new TGeoVolume("Dbar1", Dbar1b, textVolMed); + Dbar1->SetLineColor(Dcolor); + D->AddNode(Dbar1, 1, tr21); + TGeoBBox* Dbar2b = new TGeoBBox("trd_Dbar2b", 2., 4., 4.); + TGeoVolume* Dbar2 = new TGeoVolume("Dbar2", Dbar2b, textVolMed); + Dbar2->SetLineColor(Dcolor); + D->AddNode(Dbar2, 1, tr22); + D->AddNode(Dbar2, 2, tr23); + TGeoTubeSeg* Dtub1b = new TGeoTubeSeg("trd_Dtub1b", 12, 20, 4., 90., 270.); + TGeoVolume* Dtub1 = new TGeoVolume("Dtub1", (TGeoShape*) Dtub1b, textVolMed); + Dtub1->SetLineColor(Dcolor); + D->AddNode(Dtub1, 1, tr24); + + // make letter I + TGeoVolume* I = new TGeoVolumeAssembly("Ibox"); // volume for I + + TGeoBBox* Ibar1b = new TGeoBBox("trd_Ibar1b", 4., 12., 4.); // | vertical + TGeoVolume* Ibar1 = new TGeoVolume("Ibar1", Ibar1b, textVolMed); + Ibar1->SetLineColor(Icolor); + I->AddNode(Ibar1, 1, tr31); + TGeoBBox* Ibar2b = new TGeoBBox("trd_Ibar2b", 10., 4., 4.); // - top + TGeoVolume* Ibar2 = new TGeoVolume("Ibar2", Ibar2b, textVolMed); + Ibar2->SetLineColor(Icolor); + I->AddNode(Ibar2, 1, tr32); + I->AddNode(Ibar2, 2, tr33); + + + // build text block "TRD" <32> + 8 + <28> + 8 + <32> = 108 + + // TGeoBBox *trdboxb = new TGeoBBox("", 108./2, 40./2, 8./2); + // TGeoVolume *trdbox = new TGeoVolume("trdboxb", trdboxb, textVolMed); + // trdbox->SetVisibility(kFALSE); + + // TGeoVolume* trdbox[0] = new TGeoVolumeAssembly("trdbox1"); // volume for TRD text (108, 40, 8) + // TGeoVolume* trdbox[1] = new TGeoVolumeAssembly("trdbox2"); // volume for TRD text (108, 40, 8) + // TGeoVolume* trdbox[2] = new TGeoVolumeAssembly("trdbox3"); // volume for TRD text (108, 40, 8) + + TGeoTranslation* tr100 = new TGeoTranslation(38., 0., 0.); + TGeoTranslation* tr101 = new TGeoTranslation(0., 0., 0.); + TGeoTranslation* tr102 = new TGeoTranslation(-38., 0., 0.); + + // TGeoTranslation *tr103 = new TGeoTranslation( -70., 0., 0.); // on the same line + // TGeoTranslation *tr104 = new TGeoTranslation( -86., 0., 0.); // on the same line + // TGeoTranslation *tr105 = new TGeoTranslation(-102., 0., 0.); // on the same line + + TGeoTranslation* tr110 = new TGeoTranslation(0., -50., 0.); + TGeoTranslation* tr111 = new TGeoTranslation(8., -50., 0.); + TGeoTranslation* tr112 = new TGeoTranslation(-8., -50., 0.); + TGeoTranslation* tr113 = new TGeoTranslation(16., -50., 0.); + TGeoTranslation* tr114 = new TGeoTranslation(-16., -50., 0.); + + TGeoTranslation* tr200 = new TGeoTranslation(0., 0., 0.); + TGeoTranslation* tr201 = new TGeoTranslation(0., -50., 0.); + TGeoTranslation* tr202 = new TGeoTranslation(0., -100., 0.); + + TGeoTranslation* tr210 = new TGeoTranslation(0., -150., 0.); + TGeoTranslation* tr213 = new TGeoTranslation(16., -150., 0.); + TGeoTranslation* tr214 = new TGeoTranslation(-16., -150., 0.); + + // station 1 + trdbox1->AddNode(T, 1, tr100); + trdbox1->AddNode(R, 1, tr101); + trdbox1->AddNode(D, 1, tr102); + + trdbox1->AddNode(I, 1, tr110); + + // station 2 + trdbox2->AddNode(T, 1, tr100); + trdbox2->AddNode(R, 1, tr101); + trdbox2->AddNode(D, 1, tr102); + + trdbox2->AddNode(I, 1, tr111); + trdbox2->AddNode(I, 2, tr112); + + //// station 3 + // trdbox3->AddNode(T, 1, tr100); + // trdbox3->AddNode(R, 1, tr101); + // trdbox3->AddNode(D, 1, tr102); + // + // trdbox3->AddNode(I, 1, tr110); + // trdbox3->AddNode(I, 2, tr113); + // trdbox3->AddNode(I, 3, tr114); + + // station 3 + trdbox3->AddNode(T, 1, tr200); + trdbox3->AddNode(R, 1, tr201); + trdbox3->AddNode(D, 1, tr202); + + trdbox3->AddNode(I, 1, tr210); + trdbox3->AddNode(I, 2, tr213); + trdbox3->AddNode(I, 3, tr214); + + // TGeoScale *sc100 = new TGeoScale( 36./50., 36./50., 1.); // text is vertical 50 cm, H-bar opening is 36 cm + // + // // scale text + // TGeoHMatrix *mat100 = new TGeoHMatrix(""); + // TGeoHMatrix *mat101 = new TGeoHMatrix(""); + // TGeoHMatrix *mat102 = new TGeoHMatrix(""); + // (*mat100) = (*tr100) * (*sc100); + // (*mat101) = (*tr101) * (*sc100); + // (*mat102) = (*tr102) * (*sc100); + // + // trdbox->AddNode(T, 1, mat100); + // trdbox->AddNode(R, 1, mat101); + // trdbox->AddNode(D, 1, mat102); + + // // final placement + // // TGeoTranslation *tr103 = new TGeoTranslation(0., 400., 500.); + // gGeoMan->GetVolume(geoVersion)->AddNode(trdbox, 1, new TGeoTranslation(0., 400., 500.)); + // gGeoMan->GetVolume(geoVersion)->AddNode(trdbox, 2, new TGeoTranslation(0., 500., 600.)); + // gGeoMan->GetVolume(geoVersion)->AddNode(trdbox, 3, new TGeoTranslation(0., 600., 700.)); + + // return trdbox; +} + + +void create_box_supports() +{ + const TString trd_01 = "support_trd1"; + TGeoVolume* trd_1 = new TGeoVolumeAssembly(trd_01); + + const TString trd_02 = "support_trd2"; + TGeoVolume* trd_2 = new TGeoVolumeAssembly(trd_02); + + const TString trd_03 = "support_trd3"; + TGeoVolume* trd_3 = new TGeoVolumeAssembly(trd_03); + + // const TString trdSupport = "supportframe"; + // TGeoVolume* trdsupport = new TGeoVolumeAssembly(trdSupport); + // + // trdsupport->AddNode(trd_1, 1); + // trdsupport->AddNode(trd_2, 2); + // trdsupport->AddNode(trd_3, 3); + + TGeoMedium* keepVolMed = gGeoMan->GetMedium(KeepingVolumeMedium); + TGeoMedium* aluminiumVolMed = gGeoMan->GetMedium(AluminiumVolumeMedium); // define Volume Medium + + const Int_t I_height = 40; // cm // I profile properties + const Int_t I_width = 30; // cm // I profile properties + const Int_t I_thick = 2; // cm // I profile properties + + const Double_t BeamHeight = 570; // beamline is at 5.7m above the floor + const Double_t PlatformHeight = 234; // platform is 2.34m above the floor + const Double_t PlatformOffset = 1; // distance to platform + + // Double_t AperX[3] = { 450., 550., 600.}; // 100 cm modules // inner aperture in X of support structure for stations 1,2,3 + // Double_t AperY[3] = { 350., 450., 500.}; // 100 cm modules // inner aperture in Y of support structure for stations 1,2,3 + + const Double_t AperX[3] = {4.5 * DetectorSizeX[1], 5.5 * DetectorSizeX[1], + 6 * DetectorSizeX[1]}; // inner aperture in X of support structure for stations 1,2,3 + const Double_t AperY[3] = {3.5 * DetectorSizeY[1], 4.5 * DetectorSizeY[1], + 5 * DetectorSizeY[1]}; // inner aperture in Y of support structure for stations 1,2,3 + // platform + const Double_t AperYbot[3] = {BeamHeight - (PlatformHeight + PlatformOffset + I_height), 4.5 * DetectorSizeY[1], + 5 * DetectorSizeY[1]}; // inner aperture for station1 + + const Double_t xBarPosYtop[3] = {AperY[0] + I_height / 2., AperY[1] + I_height / 2., AperY[2] + I_height / 2.}; + const Double_t xBarPosYbot[3] = {AperYbot[0] + I_height / 2., xBarPosYtop[1], xBarPosYtop[2]}; + + const Double_t zBarPosYtop[3] = {AperY[0] + I_height - I_width / 2., AperY[1] + I_height - I_width / 2., + AperY[2] + I_height - I_width / 2.}; + const Double_t zBarPosYbot[3] = {AperYbot[0] + I_height - I_width / 2., zBarPosYtop[1], zBarPosYtop[2]}; + + Double_t PilPosX; + Double_t PilPosZ[6]; // PilPosZ + + PilPosZ[0] = LayerPosition[0] + I_width / 2.; + PilPosZ[1] = LayerPosition[3] - I_width / 2. + LayerThickness; + PilPosZ[2] = LayerPosition[4] + I_width / 2.; + PilPosZ[3] = LayerPosition[7] - I_width / 2. + LayerThickness; + PilPosZ[4] = LayerPosition[8] + I_width / 2.; + PilPosZ[5] = LayerPosition[9] - I_width / 2. + LayerThickness; + + // cout << "PilPosZ[0]: " << PilPosZ[0] << endl; + // cout << "PilPosZ[1]: " << PilPosZ[1] << endl; + + TGeoRotation* rotx090 = new TGeoRotation("rotx090"); + rotx090->RotateX(90.); // rotate 90 deg around x-axis + TGeoRotation* roty090 = new TGeoRotation("roty090"); + roty090->RotateY(90.); // rotate 90 deg around y-axis + TGeoRotation* rotz090 = new TGeoRotation("rotz090"); + rotz090->RotateZ(90.); // rotate 90 deg around y-axis + TGeoRotation* roty270 = new TGeoRotation("roty270"); + roty270->RotateY(270.); // rotate 270 deg around y-axis + + TGeoRotation* rotzx01 = new TGeoRotation("rotzx01"); + rotzx01->RotateZ(90.); // rotate 90 deg around z-axis + rotzx01->RotateX(90.); // rotate 90 deg around x-axis + + TGeoRotation* rotzx02 = new TGeoRotation("rotzx02"); + rotzx02->RotateZ(270.); // rotate 270 deg around z-axis + rotzx02->RotateX(90.); // rotate 90 deg around x-axis + + Double_t ang1 = atan(3. / 4.) * 180. / acos(-1.); + // cout << "DEDE " << ang1 << endl; + // Double_t sin1 = acos(-1.); + // cout << "DEDE " << sin1 << endl; + TGeoRotation* rotx080 = new TGeoRotation("rotx080"); + rotx080->RotateX(90. - ang1); // rotate 80 deg around x-axis + TGeoRotation* rotx100 = new TGeoRotation("rotx100"); + rotx100->RotateX(90. + ang1); // rotate 100 deg around x-axis + + TGeoRotation* rotxy01 = new TGeoRotation("rotxy01"); + rotxy01->RotateX(90.); // rotate 90 deg around x-axis + rotxy01->RotateZ(-ang1); // rotate ang1 around rotated y-axis + + TGeoRotation* rotxy02 = new TGeoRotation("rotxy02"); + rotxy02->RotateX(90.); // rotate 90 deg around x-axis + rotxy02->RotateZ(ang1); // rotate ang1 around rotated y-axis + + + //------------------- + // vertical pillars (Y) + //------------------- + + // station 1 + if (ShowLayer[0]) // if geometry contains layer 1 (1st layer of station 1) + { + // TGeoBBox* trd_I_vert1_keep = new TGeoBBox("", I_thick /2., I_height /2. - I_thick, (BeamHeight + (AperY[0]+I_height) ) /2.); + TGeoBBox* trd_I_vert1_keep = new TGeoBBox("trd_I_vert1_keep", I_thick / 2., I_height / 2. - I_thick, + ((AperYbot[0] + I_height) + (AperY[0] + I_height)) / 2.); + TGeoVolume* trd_I_vert1 = new TGeoVolume("trd_I_y11", trd_I_vert1_keep, aluminiumVolMed); + // TGeoBBox* trd_I_vert2_keep = new TGeoBBox("", I_width /2., I_thick /2., (BeamHeight + (AperY[0]+I_height) ) /2.); + TGeoBBox* trd_I_vert2_keep = new TGeoBBox("trd_I_vert2_keep", I_width / 2., I_thick / 2., + ((AperYbot[0] + I_height) + (AperY[0] + I_height)) / 2.); + TGeoVolume* trd_I_vert2 = new TGeoVolume("trd_I_y12", trd_I_vert2_keep, aluminiumVolMed); + + trd_I_vert1->SetLineColor(kGreen); // kBlue); // Yellow); // kOrange); + trd_I_vert2->SetLineColor(kGreen); // kBlue); // Yellow); // kOrange); + + TGeoTranslation* ty01 = new TGeoTranslation("ty01", 0., 0., 0.); + TGeoTranslation* ty02 = new TGeoTranslation("ty02", 0., (I_height - I_thick) / 2., 0.); + TGeoTranslation* ty03 = new TGeoTranslation("ty03", 0., -(I_height - I_thick) / 2., 0.); + + // TGeoBBox* trd_I_vert_vol1_keep = new TGeoBBox("", I_width /2., I_height /2., (BeamHeight + (AperY[0]+I_height) ) /2.); + TGeoBBox* trd_I_vert_vol1_keep = new TGeoBBox("trd_I_vert_vol1_keep", I_width / 2., I_height / 2., + ((AperYbot[0] + I_height) + (AperY[0] + I_height)) / 2.); + TGeoVolume* trd_I_vert_vol1 = new TGeoVolume("trd_I_y10", trd_I_vert_vol1_keep, keepVolMed); + + // set green color for keeping volume of I profile, seen with gGeoManager->SetVisLevel(2) + trd_I_vert_vol1->SetLineColor(kGreen); + + // build I-bar trd_I_vert_vol1 + trd_I_vert_vol1->AddNode(trd_I_vert1, 1, ty01); + trd_I_vert_vol1->AddNode(trd_I_vert2, 2, ty02); + trd_I_vert_vol1->AddNode(trd_I_vert2, 3, ty03); + + // close gap to horizontal z-bars + TGeoBBox* trd_I_vert3_keep = + new TGeoBBox("trd_I_vert3_keep", (I_width - I_thick) / 2. / 2., I_height / 2. - I_thick, I_thick / 2.); + TGeoVolume* trd_I_vert3 = new TGeoVolume("trd_I_y13", trd_I_vert3_keep, aluminiumVolMed); + trd_I_vert3->SetLineColor(kGreen); + // TGeoTranslation *ty04 = new TGeoTranslation("ty04", (I_thick/2. + (I_width-I_thick)/2./2.), 0., -( (AperYbot[0]+I_height) + (AperY[0]+I_height) - I_width) /2.); // top + // TGeoTranslation *ty05 = new TGeoTranslation("ty05", (I_thick/2. + (I_width-I_thick)/2./2.), 0., ( (AperYbot[0]+I_height) + (AperY[0]+I_height) - I_width) /2.); // bottom + TGeoTranslation* ty04 = new TGeoTranslation("ty04", (I_thick / 2. + (I_width - I_thick) / 2. / 2.), 0., + -(zBarPosYbot[0] + zBarPosYtop[0]) / 2.); // top + TGeoTranslation* ty05 = new TGeoTranslation("ty05", (I_thick / 2. + (I_width - I_thick) / 2. / 2.), 0., + (zBarPosYbot[0] + zBarPosYtop[0]) / 2.); // bottom + trd_I_vert_vol1->AddNode(trd_I_vert3, 4, ty04); + trd_I_vert_vol1->AddNode(trd_I_vert3, 5, ty05); + + PilPosX = AperX[0]; + + TGeoCombiTrans* trd_I_vert_combi01 = new TGeoCombiTrans( + (PilPosX + I_height / 2.), -((AperYbot[0] + I_height) - (AperY[0] + I_height)) / 2., PilPosZ[0], rotzx01); + trd_1->AddNode(trd_I_vert_vol1, 11, trd_I_vert_combi01); + TGeoCombiTrans* trd_I_vert_combi02 = new TGeoCombiTrans( + -(PilPosX + I_height / 2.), -((AperYbot[0] + I_height) - (AperY[0] + I_height)) / 2., PilPosZ[0], rotzx01); + trd_1->AddNode(trd_I_vert_vol1, 12, trd_I_vert_combi02); + TGeoCombiTrans* trd_I_vert_combi03 = new TGeoCombiTrans( + (PilPosX + I_height / 2.), -((AperYbot[0] + I_height) - (AperY[0] + I_height)) / 2., PilPosZ[1], rotzx02); + trd_1->AddNode(trd_I_vert_vol1, 13, trd_I_vert_combi03); + TGeoCombiTrans* trd_I_vert_combi04 = new TGeoCombiTrans( + -(PilPosX + I_height / 2.), -((AperYbot[0] + I_height) - (AperY[0] + I_height)) / 2., PilPosZ[1], rotzx02); + trd_1->AddNode(trd_I_vert_vol1, 14, trd_I_vert_combi04); + } + + // station 2 + if (ShowLayer[4]) // if geometry contains layer 5 (1st layer of station 2) + { + TGeoBBox* trd_I_vert1_keep = new TGeoBBox("trd_I_vert1_keep", I_thick / 2., I_height / 2. - I_thick, + (BeamHeight + (AperY[1] + I_height)) / 2.); + TGeoVolume* trd_I_vert1 = new TGeoVolume("trd_I_y21", trd_I_vert1_keep, aluminiumVolMed); + TGeoBBox* trd_I_vert2_keep = + new TGeoBBox("trd_I_vert2_keep", I_width / 2., I_thick / 2., (BeamHeight + (AperY[1] + I_height)) / 2.); + TGeoVolume* trd_I_vert2 = new TGeoVolume("trd_I_y22", trd_I_vert2_keep, aluminiumVolMed); + trd_I_vert1->SetLineColor(kGreen); + trd_I_vert2->SetLineColor(kGreen); + + TGeoTranslation* ty01 = new TGeoTranslation("ty01", 0., 0., 0.); + TGeoTranslation* ty02 = new TGeoTranslation("ty02", 0., (I_height - I_thick) / 2., 0.); + TGeoTranslation* ty03 = new TGeoTranslation("ty03", 0., -(I_height - I_thick) / 2., 0.); + + TGeoBBox* trd_I_vert_vol1_keep = + new TGeoBBox("trd_I_vert_vol1_keep", I_width / 2., I_height / 2., (BeamHeight + (AperY[1] + I_height)) / 2.); + TGeoVolume* trd_I_vert_vol1 = new TGeoVolume("trd_I_y20", trd_I_vert_vol1_keep, keepVolMed); + + // set green color for keeping volume of I profile, seen with gGeoManager->SetVisLevel(2) + trd_I_vert_vol1->SetLineColor(kGreen); + + // build I-bar trd_I_vert_vol1 + trd_I_vert_vol1->AddNode(trd_I_vert1, 1, ty01); + trd_I_vert_vol1->AddNode(trd_I_vert2, 2, ty02); + trd_I_vert_vol1->AddNode(trd_I_vert2, 3, ty03); + + // close gap to horizontal z-bars + TGeoBBox* trd_I_vert3_keep = + new TGeoBBox("trd_I_vert3_keep", (I_width - I_thick) / 2. / 2., I_height / 2. - I_thick, I_thick / 2.); + TGeoVolume* trd_I_vert3 = new TGeoVolume("trd_I_y23", trd_I_vert3_keep, aluminiumVolMed); + trd_I_vert3->SetLineColor(kGreen); + TGeoTranslation* ty04 = new TGeoTranslation("ty04", (I_thick / 2. + (I_width - I_thick) / 2. / 2.), 0., + -(BeamHeight + (AperY[1] + I_height) - I_width) / 2.); // top + TGeoTranslation* ty05 = new TGeoTranslation("ty05", (I_thick / 2. + (I_width - I_thick) / 2. / 2.), 0., + -(BeamHeight - (AperY[1] + I_height)) / 2. + zBarPosYbot[1]); // bottom + trd_I_vert_vol1->AddNode(trd_I_vert3, 4, ty04); + trd_I_vert_vol1->AddNode(trd_I_vert3, 5, ty05); + + PilPosX = AperX[1]; + + TGeoCombiTrans* trd_I_vert_combi01 = + new TGeoCombiTrans((PilPosX + I_height / 2.), -(BeamHeight - (AperY[1] + I_height)) / 2., PilPosZ[2], rotzx01); + trd_2->AddNode(trd_I_vert_vol1, 21, trd_I_vert_combi01); + TGeoCombiTrans* trd_I_vert_combi02 = + new TGeoCombiTrans(-(PilPosX + I_height / 2.), -(BeamHeight - (AperY[1] + I_height)) / 2., PilPosZ[2], rotzx01); + trd_2->AddNode(trd_I_vert_vol1, 22, trd_I_vert_combi02); + TGeoCombiTrans* trd_I_vert_combi03 = + new TGeoCombiTrans((PilPosX + I_height / 2.), -(BeamHeight - (AperY[1] + I_height)) / 2., PilPosZ[3], rotzx02); + trd_2->AddNode(trd_I_vert_vol1, 23, trd_I_vert_combi03); + TGeoCombiTrans* trd_I_vert_combi04 = + new TGeoCombiTrans(-(PilPosX + I_height / 2.), -(BeamHeight - (AperY[1] + I_height)) / 2., PilPosZ[3], rotzx02); + trd_2->AddNode(trd_I_vert_vol1, 24, trd_I_vert_combi04); + } + + // station 3 + if (ShowLayer[8]) // if geometry contains layer 9 (1st layer of station 3) + { + TGeoBBox* trd_I_vert1_keep = new TGeoBBox("trd_I_vert1_keep", I_thick / 2., I_height / 2. - I_thick, + (BeamHeight + (AperY[2] + I_height)) / 2.); + TGeoVolume* trd_I_vert1 = new TGeoVolume("trd_I_y31", trd_I_vert1_keep, aluminiumVolMed); + TGeoBBox* trd_I_vert2_keep = + new TGeoBBox("trd_I_vert2_keep", I_width / 2., I_thick / 2., (BeamHeight + (AperY[2] + I_height)) / 2.); + TGeoVolume* trd_I_vert2 = new TGeoVolume("trd_I_y32", trd_I_vert2_keep, aluminiumVolMed); + + trd_I_vert1->SetLineColor(kGreen); + trd_I_vert2->SetLineColor(kGreen); + + TGeoTranslation* ty01 = new TGeoTranslation("ty01", 0., 0., 0.); + TGeoTranslation* ty02 = new TGeoTranslation("ty02", 0., (I_height - I_thick) / 2., 0.); + TGeoTranslation* ty03 = new TGeoTranslation("ty03", 0., -(I_height - I_thick) / 2., 0.); + + TGeoBBox* trd_I_vert_vol1_keep = + new TGeoBBox("trd_I_vert_vol1_keep", I_width / 2., I_height / 2., (BeamHeight + (AperY[2] + I_height)) / 2.); + TGeoVolume* trd_I_vert_vol1 = new TGeoVolume("trd_I_y30", trd_I_vert_vol1_keep, keepVolMed); + + // set green color for keeping volume of I profile, seen with gGeoManager->SetVisLevel(2) + trd_I_vert_vol1->SetLineColor(kGreen); + + // build I-bar trd_I_vert_vol1 + trd_I_vert_vol1->AddNode(trd_I_vert1, 1, ty01); + trd_I_vert_vol1->AddNode(trd_I_vert2, 2, ty02); + trd_I_vert_vol1->AddNode(trd_I_vert2, 3, ty03); + + // close gap to horizontal z-bars + TGeoBBox* trd_I_vert3_keep = + new TGeoBBox("trd_I_vert3_keep", (I_width - I_thick) / 2. / 2., I_height / 2. - I_thick, I_thick / 2.); + TGeoVolume* trd_I_vert3 = new TGeoVolume("trd_I_y33", trd_I_vert3_keep, aluminiumVolMed); + trd_I_vert3->SetLineColor(kGreen); + TGeoTranslation* ty04 = new TGeoTranslation("ty04", (I_thick / 2. + (I_width - I_thick) / 2. / 2.), 0., + -(BeamHeight + (AperY[2] + I_height) - I_width) / 2.); // top + TGeoTranslation* ty05 = new TGeoTranslation("ty05", (I_thick / 2. + (I_width - I_thick) / 2. / 2.), 0., + -(BeamHeight - (AperY[2] + I_height)) / 2. + zBarPosYbot[2]); // bottom + trd_I_vert_vol1->AddNode(trd_I_vert3, 4, ty04); + trd_I_vert_vol1->AddNode(trd_I_vert3, 5, ty05); + + PilPosX = AperX[2]; + + TGeoCombiTrans* trd_I_vert_combi01 = + new TGeoCombiTrans((PilPosX + I_height / 2.), -(BeamHeight - (AperY[2] + I_height)) / 2., PilPosZ[4], rotzx01); + trd_3->AddNode(trd_I_vert_vol1, 31, trd_I_vert_combi01); + TGeoCombiTrans* trd_I_vert_combi02 = + new TGeoCombiTrans(-(PilPosX + I_height / 2.), -(BeamHeight - (AperY[2] + I_height)) / 2., PilPosZ[4], rotzx01); + trd_3->AddNode(trd_I_vert_vol1, 32, trd_I_vert_combi02); + TGeoCombiTrans* trd_I_vert_combi03 = + new TGeoCombiTrans((PilPosX + I_height / 2.), -(BeamHeight - (AperY[2] + I_height)) / 2., PilPosZ[5], rotzx02); + trd_3->AddNode(trd_I_vert_vol1, 33, trd_I_vert_combi03); + TGeoCombiTrans* trd_I_vert_combi04 = + new TGeoCombiTrans(-(PilPosX + I_height / 2.), -(BeamHeight - (AperY[2] + I_height)) / 2., PilPosZ[5], rotzx02); + trd_3->AddNode(trd_I_vert_vol1, 34, trd_I_vert_combi04); + } + + + //------------------- + // horizontal supports (X) + //------------------- + + // station 1 + if (ShowLayer[0]) // if geometry contains layer 1 (1st layer of station 1) + { + TGeoBBox* trd_I_hori1_keep = new TGeoBBox("trd_I_hori1_keep", I_thick / 2., I_height / 2. - I_thick, AperX[0]); + TGeoVolume* trd_I_hori1 = new TGeoVolume("trd_I_x11", trd_I_hori1_keep, aluminiumVolMed); + TGeoBBox* trd_I_hori2_keep = new TGeoBBox("trd_I_hori2_keep", I_width / 2., I_thick / 2., AperX[0]); + TGeoVolume* trd_I_hori2 = new TGeoVolume("trd_I_x12", trd_I_hori2_keep, aluminiumVolMed); + + trd_I_hori1->SetLineColor(kRed); // Yellow); + trd_I_hori2->SetLineColor(kRed); // Yellow); + + TGeoTranslation* tx01 = new TGeoTranslation("tx01", 0., 0., 0.); + TGeoTranslation* tx02 = new TGeoTranslation("tx02", 0., (I_height - I_thick) / 2., 0.); + TGeoTranslation* tx03 = new TGeoTranslation("tx03", 0., -(I_height - I_thick) / 2., 0.); + + TGeoBBox* trd_I_hori_vol1_keep = new TGeoBBox("trd_I_hori_vol1_keep", I_width / 2., I_height / 2., AperX[0]); + TGeoVolume* trd_I_hori_vol1 = new TGeoVolume("trd_I_x10", trd_I_hori_vol1_keep, keepVolMed); + + // set red color for keeping volume of I profile, seen with gGeoManager->SetVisLevel(2) + trd_I_hori_vol1->SetLineColor(kRed); + + // build I-bar trd_I_hori_vol1 + trd_I_hori_vol1->AddNode(trd_I_hori1, 1, tx01); + trd_I_hori_vol1->AddNode(trd_I_hori2, 2, tx02); + trd_I_hori_vol1->AddNode(trd_I_hori2, 3, tx03); + + TGeoCombiTrans* trd_I_hori_combi01 = new TGeoCombiTrans(0., xBarPosYtop[0], PilPosZ[0], roty090); + trd_1->AddNode(trd_I_hori_vol1, 11, trd_I_hori_combi01); + TGeoCombiTrans* trd_I_hori_combi02 = new TGeoCombiTrans(0., -xBarPosYbot[0], PilPosZ[0], roty090); + trd_1->AddNode(trd_I_hori_vol1, 12, trd_I_hori_combi02); + TGeoCombiTrans* trd_I_hori_combi03 = new TGeoCombiTrans(0., xBarPosYtop[0], PilPosZ[1], roty090); + trd_1->AddNode(trd_I_hori_vol1, 13, trd_I_hori_combi03); + TGeoCombiTrans* trd_I_hori_combi04 = new TGeoCombiTrans(0., -xBarPosYbot[0], PilPosZ[1], roty090); + trd_1->AddNode(trd_I_hori_vol1, 14, trd_I_hori_combi04); + } + + // station 2 + if (ShowLayer[4]) // if geometry contains layer 5 (1st layer of station 2) + { + TGeoBBox* trd_I_hori1_keep = new TGeoBBox("trd_I_hori1_keep", I_thick / 2., I_height / 2. - I_thick, AperX[1]); + TGeoVolume* trd_I_hori1 = new TGeoVolume("trd_I_x21", trd_I_hori1_keep, aluminiumVolMed); + TGeoBBox* trd_I_hori2_keep = new TGeoBBox("trd_I_hori2_keep", I_width / 2., I_thick / 2., AperX[1]); + TGeoVolume* trd_I_hori2 = new TGeoVolume("trd_I_x22", trd_I_hori2_keep, aluminiumVolMed); + + trd_I_hori1->SetLineColor(kRed); + trd_I_hori2->SetLineColor(kRed); + + TGeoTranslation* tx01 = new TGeoTranslation("tx01", 0., 0., 0.); + TGeoTranslation* tx02 = new TGeoTranslation("tx02", 0., (I_height - I_thick) / 2., 0.); + TGeoTranslation* tx03 = new TGeoTranslation("tx03", 0., -(I_height - I_thick) / 2., 0.); + + TGeoBBox* trd_I_hori_vol1_keep = new TGeoBBox("trd_I_hori_vol1_keep", I_width / 2., I_height / 2., AperX[1]); + TGeoVolume* trd_I_hori_vol1 = new TGeoVolume("trd_I_x20", trd_I_hori_vol1_keep, keepVolMed); + + // set red color for keeping volume of I profile, seen with gGeoManager->SetVisLevel(2) + trd_I_hori_vol1->SetLineColor(kRed); + + // build I-bar trd_I_hori_vol1 + trd_I_hori_vol1->AddNode(trd_I_hori1, 1, tx01); + trd_I_hori_vol1->AddNode(trd_I_hori2, 2, tx02); + trd_I_hori_vol1->AddNode(trd_I_hori2, 3, tx03); + + TGeoCombiTrans* trd_I_hori_combi01 = new TGeoCombiTrans(0., xBarPosYtop[1], PilPosZ[2], roty090); + trd_2->AddNode(trd_I_hori_vol1, 21, trd_I_hori_combi01); + TGeoCombiTrans* trd_I_hori_combi02 = new TGeoCombiTrans(0., -xBarPosYbot[1], PilPosZ[2], roty090); + trd_2->AddNode(trd_I_hori_vol1, 22, trd_I_hori_combi02); + TGeoCombiTrans* trd_I_hori_combi03 = new TGeoCombiTrans(0., xBarPosYtop[1], PilPosZ[3], roty090); + trd_2->AddNode(trd_I_hori_vol1, 23, trd_I_hori_combi03); + TGeoCombiTrans* trd_I_hori_combi04 = new TGeoCombiTrans(0., -xBarPosYbot[1], PilPosZ[3], roty090); + trd_2->AddNode(trd_I_hori_vol1, 24, trd_I_hori_combi04); + } + + // station 3 + if (ShowLayer[8]) // if geometry contains layer 9 (1st layer of station 3) + { + TGeoBBox* trd_I_hori1_keep = new TGeoBBox("trd_I_hori1_keep", I_thick / 2., I_height / 2. - I_thick, AperX[2]); + TGeoVolume* trd_I_hori1 = new TGeoVolume("trd_I_x31", trd_I_hori1_keep, aluminiumVolMed); + TGeoBBox* trd_I_hori2_keep = new TGeoBBox("trd_I_hori2_keep", I_width / 2., I_thick / 2., AperX[2]); + TGeoVolume* trd_I_hori2 = new TGeoVolume("trd_I_x32", trd_I_hori2_keep, aluminiumVolMed); + + trd_I_hori1->SetLineColor(kRed); + trd_I_hori2->SetLineColor(kRed); + + TGeoTranslation* tx01 = new TGeoTranslation("tx01", 0., 0., 0.); + TGeoTranslation* tx02 = new TGeoTranslation("tx02", 0., (I_height - I_thick) / 2., 0.); + TGeoTranslation* tx03 = new TGeoTranslation("tx03", 0., -(I_height - I_thick) / 2., 0.); + + TGeoBBox* trd_I_hori_vol1_keep = new TGeoBBox("trd_I_hori_vol1_keep", I_width / 2., I_height / 2., AperX[2]); + TGeoVolume* trd_I_hori_vol1 = new TGeoVolume("trd_I_x30", trd_I_hori_vol1_keep, keepVolMed); + + // set red color for keeping volume of I profile, seen with gGeoManager->SetVisLevel(2) + trd_I_hori_vol1->SetLineColor(kRed); + + // build I-bar trd_I_hori_vol1 + trd_I_hori_vol1->AddNode(trd_I_hori1, 1, tx01); + trd_I_hori_vol1->AddNode(trd_I_hori2, 2, tx02); + trd_I_hori_vol1->AddNode(trd_I_hori2, 3, tx03); + + TGeoCombiTrans* trd_I_hori_combi01 = new TGeoCombiTrans(0., xBarPosYtop[2], PilPosZ[4], roty090); + trd_3->AddNode(trd_I_hori_vol1, 31, trd_I_hori_combi01); + TGeoCombiTrans* trd_I_hori_combi02 = new TGeoCombiTrans(0., -xBarPosYbot[2], PilPosZ[4], roty090); + trd_3->AddNode(trd_I_hori_vol1, 32, trd_I_hori_combi02); + TGeoCombiTrans* trd_I_hori_combi03 = new TGeoCombiTrans(0., xBarPosYtop[2], PilPosZ[5], roty090); + trd_3->AddNode(trd_I_hori_vol1, 33, trd_I_hori_combi03); + TGeoCombiTrans* trd_I_hori_combi04 = new TGeoCombiTrans(0., -xBarPosYbot[2], PilPosZ[5], roty090); + trd_3->AddNode(trd_I_hori_vol1, 34, trd_I_hori_combi04); + } + + + //------------------- + // horizontal supports (Z) + //------------------- + + // station 1 + if (ShowLayer[0]) // if geometry contains layer 1 (1st layer of station 1) + { + TGeoBBox* trd_I_slope1_keep = new TGeoBBox("trd_I_slope1_keep", I_thick / 2., I_height / 2. - I_thick, + (PilPosZ[1] - PilPosZ[0] - I_width) / 2.); + TGeoVolume* trd_I_slope1 = new TGeoVolume("trd_I_z11", trd_I_slope1_keep, aluminiumVolMed); + TGeoBBox* trd_I_slope2_keep = + new TGeoBBox("trd_I_slope2_keep", I_width / 2., I_thick / 2., (PilPosZ[1] - PilPosZ[0] - I_width) / 2.); + TGeoVolume* trd_I_slope2 = new TGeoVolume("trd_I_z12", trd_I_slope2_keep, aluminiumVolMed); + + trd_I_slope1->SetLineColor(kYellow); + trd_I_slope2->SetLineColor(kYellow); + + TGeoTranslation* tz01 = new TGeoTranslation("tz01", 0., 0., 0.); + TGeoTranslation* tz02 = new TGeoTranslation("tz02", 0., (I_height - I_thick) / 2., 0.); + TGeoTranslation* tz03 = new TGeoTranslation("tz03", 0., -(I_height - I_thick) / 2., 0.); + + TGeoBBox* trd_I_slope_vol1_keep = + new TGeoBBox("trd_I_slope_vol1_keep", I_width / 2., I_height / 2., (PilPosZ[1] - PilPosZ[0] - I_width) / 2.); + TGeoVolume* trd_I_slope_vol1 = new TGeoVolume("trd_I_z10", trd_I_slope_vol1_keep, keepVolMed); + + // set yellow color for keeping volume of I profile, seen with gGeoManager->SetVisLevel(2) + trd_I_slope_vol1->SetLineColor(kYellow); + + // build I-bar trd_I_slope_vol1 + trd_I_slope_vol1->AddNode(trd_I_slope1, 1, tz01); + trd_I_slope_vol1->AddNode(trd_I_slope2, 2, tz02); + trd_I_slope_vol1->AddNode(trd_I_slope2, 3, tz03); + + PilPosX = AperX[0]; + + TGeoCombiTrans* trd_I_slope_combi01 = + new TGeoCombiTrans((PilPosX + I_height / 2.), zBarPosYtop[0], (PilPosZ[0] + PilPosZ[1]) / 2., rotz090); + trd_1->AddNode(trd_I_slope_vol1, 11, trd_I_slope_combi01); + TGeoCombiTrans* trd_I_slope_combi02 = + new TGeoCombiTrans(-(PilPosX + I_height / 2.), zBarPosYtop[0], (PilPosZ[0] + PilPosZ[1]) / 2., rotz090); + trd_1->AddNode(trd_I_slope_vol1, 12, trd_I_slope_combi02); + TGeoCombiTrans* trd_I_slope_combi03 = + new TGeoCombiTrans((PilPosX + I_height / 2.), -zBarPosYbot[0], (PilPosZ[0] + PilPosZ[1]) / 2., rotz090); + trd_1->AddNode(trd_I_slope_vol1, 13, trd_I_slope_combi03); + TGeoCombiTrans* trd_I_slope_combi04 = + new TGeoCombiTrans(-(PilPosX + I_height / 2.), -zBarPosYbot[0], (PilPosZ[0] + PilPosZ[1]) / 2., rotz090); + trd_1->AddNode(trd_I_slope_vol1, 14, trd_I_slope_combi04); + } + + // station 2 + if (ShowLayer[4]) // if geometry contains layer 5 (1st layer of station 2) + { + TGeoBBox* trd_I_slope1_keep = new TGeoBBox("trd_I_slope1_keep", I_thick / 2., I_height / 2. - I_thick, + (PilPosZ[3] - PilPosZ[2] - I_width) / 2.); + TGeoVolume* trd_I_slope1 = new TGeoVolume("trd_I_z21", trd_I_slope1_keep, aluminiumVolMed); + TGeoBBox* trd_I_slope2_keep = + new TGeoBBox("trd_I_slope2_keep", I_width / 2., I_thick / 2., (PilPosZ[3] - PilPosZ[2] - I_width) / 2.); + TGeoVolume* trd_I_slope2 = new TGeoVolume("trd_I_z22", trd_I_slope2_keep, aluminiumVolMed); + + trd_I_slope1->SetLineColor(kYellow); + trd_I_slope2->SetLineColor(kYellow); + + TGeoTranslation* tz01 = new TGeoTranslation("tz01", 0., 0., 0.); + TGeoTranslation* tz02 = new TGeoTranslation("tz02", 0., (I_height - I_thick) / 2., 0.); + TGeoTranslation* tz03 = new TGeoTranslation("tz03", 0., -(I_height - I_thick) / 2., 0.); + + TGeoBBox* trd_I_slope_vol1_keep = + new TGeoBBox("trd_I_slope_vol1_keep", I_width / 2., I_height / 2., (PilPosZ[3] - PilPosZ[2] - I_width) / 2.); + TGeoVolume* trd_I_slope_vol1 = new TGeoVolume("trd_I_z20", trd_I_slope_vol1_keep, keepVolMed); + + // set yellow color for keeping volume of I profile, seen with gGeoManager->SetVisLevel(2) + trd_I_slope_vol1->SetLineColor(kYellow); + + // build I-bar trd_I_slope_vol1 + trd_I_slope_vol1->AddNode(trd_I_slope1, 1, tz01); + trd_I_slope_vol1->AddNode(trd_I_slope2, 2, tz02); + trd_I_slope_vol1->AddNode(trd_I_slope2, 3, tz03); + + PilPosX = AperX[1]; + + TGeoCombiTrans* trd_I_slope_combi01 = + new TGeoCombiTrans((PilPosX + I_height / 2.), zBarPosYtop[1], (PilPosZ[2] + PilPosZ[3]) / 2., rotz090); + trd_2->AddNode(trd_I_slope_vol1, 21, trd_I_slope_combi01); + TGeoCombiTrans* trd_I_slope_combi02 = + new TGeoCombiTrans(-(PilPosX + I_height / 2.), zBarPosYtop[1], (PilPosZ[2] + PilPosZ[3]) / 2., rotz090); + trd_2->AddNode(trd_I_slope_vol1, 22, trd_I_slope_combi02); + TGeoCombiTrans* trd_I_slope_combi03 = + new TGeoCombiTrans((PilPosX + I_height / 2.), -zBarPosYbot[1], (PilPosZ[2] + PilPosZ[3]) / 2., rotz090); + trd_2->AddNode(trd_I_slope_vol1, 23, trd_I_slope_combi03); + TGeoCombiTrans* trd_I_slope_combi04 = + new TGeoCombiTrans(-(PilPosX + I_height / 2.), -zBarPosYbot[1], (PilPosZ[2] + PilPosZ[3]) / 2., rotz090); + trd_2->AddNode(trd_I_slope_vol1, 24, trd_I_slope_combi04); + } + + // station 3 + if (ShowLayer[8]) // if geometry contains layer 9 (1st layer of station 3) + { + TGeoBBox* trd_I_slope1_keep = new TGeoBBox("trd_I_slope1_keep", I_thick / 2., I_height / 2. - I_thick, + (PilPosZ[5] - PilPosZ[4] - I_width) / 2.); + TGeoVolume* trd_I_slope1 = new TGeoVolume("trd_I_z31", trd_I_slope1_keep, aluminiumVolMed); + TGeoBBox* trd_I_slope2_keep = + new TGeoBBox("trd_I_slope2_keep", I_width / 2., I_thick / 2., (PilPosZ[5] - PilPosZ[4] - I_width) / 2.); + TGeoVolume* trd_I_slope2 = new TGeoVolume("trd_I_z32", trd_I_slope2_keep, aluminiumVolMed); + + trd_I_slope1->SetLineColor(kYellow); + trd_I_slope2->SetLineColor(kYellow); + + TGeoTranslation* tz01 = new TGeoTranslation("tz01", 0., 0., 0.); + TGeoTranslation* tz02 = new TGeoTranslation("tz02", 0., (I_height - I_thick) / 2., 0.); + TGeoTranslation* tz03 = new TGeoTranslation("tz03", 0., -(I_height - I_thick) / 2., 0.); + + TGeoBBox* trd_I_slope_vol1_keep = + new TGeoBBox("trd_I_slope_vol1_keep", I_width / 2., I_height / 2., (PilPosZ[5] - PilPosZ[4] - I_width) / 2.); + TGeoVolume* trd_I_slope_vol1 = new TGeoVolume("trd_I_z30", trd_I_slope_vol1_keep, keepVolMed); + + // set yellow color for keeping volume of I profile, seen with gGeoManager->SetVisLevel(2) + trd_I_slope_vol1->SetLineColor(kYellow); + + // build I-bar trd_I_slope_vol1 + trd_I_slope_vol1->AddNode(trd_I_slope1, 1, tz01); + trd_I_slope_vol1->AddNode(trd_I_slope2, 2, tz02); + trd_I_slope_vol1->AddNode(trd_I_slope2, 3, tz03); + + PilPosX = AperX[2]; + + TGeoCombiTrans* trd_I_slope_combi01 = + new TGeoCombiTrans((PilPosX + I_height / 2.), zBarPosYtop[2], (PilPosZ[4] + PilPosZ[5]) / 2., rotz090); + trd_3->AddNode(trd_I_slope_vol1, 31, trd_I_slope_combi01); + TGeoCombiTrans* trd_I_slope_combi02 = + new TGeoCombiTrans(-(PilPosX + I_height / 2.), zBarPosYtop[2], (PilPosZ[4] + PilPosZ[5]) / 2., rotz090); + trd_3->AddNode(trd_I_slope_vol1, 32, trd_I_slope_combi02); + TGeoCombiTrans* trd_I_slope_combi03 = + new TGeoCombiTrans((PilPosX + I_height / 2.), -zBarPosYbot[2], (PilPosZ[4] + PilPosZ[5]) / 2., rotz090); + trd_3->AddNode(trd_I_slope_vol1, 33, trd_I_slope_combi03); + TGeoCombiTrans* trd_I_slope_combi04 = + new TGeoCombiTrans(-(PilPosX + I_height / 2.), -zBarPosYbot[2], (PilPosZ[4] + PilPosZ[5]) / 2., rotz090); + trd_3->AddNode(trd_I_slope_vol1, 34, trd_I_slope_combi04); + } + + if (IncludeLabels) { + + Int_t text_height = 40; + Int_t text_thickness = 8; + + TGeoTranslation* tr200 = new TGeoTranslation(0., (AperY[0] + I_height + text_height / 2.), + PilPosZ[0] - I_width / 2. + text_thickness / 2.); + TGeoTranslation* tr201 = new TGeoTranslation(0., (AperY[1] + I_height + text_height / 2.), + PilPosZ[2] - I_width / 2. + text_thickness / 2.); + TGeoTranslation* tr202 = new TGeoTranslation(0., (AperY[2] + I_height + text_height / 2.), + PilPosZ[4] - I_width / 2. + text_thickness / 2.); + TGeoCombiTrans* tr203 = + new TGeoCombiTrans(-(AperX[0] + I_height + text_thickness / 2.), + (AperY[0] + I_height - I_width - text_height / 2.), (PilPosZ[0] + PilPosZ[1]) / 2., roty090); + TGeoCombiTrans* tr204 = + new TGeoCombiTrans(-(AperX[1] + I_height + text_thickness / 2.), + (AperY[1] + I_height - I_width - text_height / 2.), (PilPosZ[2] + PilPosZ[3]) / 2., roty090); + TGeoCombiTrans* tr205 = + new TGeoCombiTrans(-(AperX[2] + I_height + text_thickness / 2.), + (AperY[2] + I_height - I_width - text_height / 2.), (PilPosZ[4] + PilPosZ[5]) / 2., roty090); + TGeoCombiTrans* tr206 = + new TGeoCombiTrans((AperX[0] + I_height + text_thickness / 2.), + (AperY[0] + I_height - I_width - text_height / 2.), (PilPosZ[0] + PilPosZ[1]) / 2., roty270); + TGeoCombiTrans* tr207 = + new TGeoCombiTrans((AperX[1] + I_height + text_thickness / 2.), + (AperY[1] + I_height - I_width - text_height / 2.), (PilPosZ[2] + PilPosZ[3]) / 2., roty270); + TGeoCombiTrans* tr208 = + new TGeoCombiTrans((AperX[2] + I_height + text_thickness / 2.), + (AperY[2] + I_height - I_width - text_height / 2.), (PilPosZ[4] + PilPosZ[5]) / 2., roty270); + + TGeoVolume* trdbox1 = new TGeoVolumeAssembly("trdbox1"); // volume for TRD text (108, 40, 8) + TGeoVolume* trdbox2 = new TGeoVolumeAssembly("trdbox2"); // volume for TRD text (108, 40, 8) + TGeoVolume* trdbox3 = new TGeoVolumeAssembly("trdbox3"); // volume for TRD text (108, 40, 8) + add_trd_labels(trdbox1, trdbox2, trdbox3); + + // final placement + if (ShowLayer[0]) // if geometry contains layer 1 (1st layer of station 1) + { + // trd_1->AddNode(trdbox1, 1, tr200); + trd_1->AddNode(trdbox1, 4, tr203); + trd_1->AddNode(trdbox1, 7, tr206); + } + if (ShowLayer[4]) // if geometry contains layer 5 (1st layer of station 2) + { + // trd_2->AddNode(trdbox2, 2, tr201); + trd_2->AddNode(trdbox2, 5, tr204); + trd_2->AddNode(trdbox2, 8, tr207); + } + if (ShowLayer[8]) // if geometry contains layer 9 (1st layer of station 3) + { + // trd_3->AddNode(trdbox3, 3, tr202); + trd_3->AddNode(trdbox3, 6, tr205); + trd_3->AddNode(trdbox3, 9, tr208); + } + } + + if (ShowLayer[0]) // if geometry contains layer 1 (1st layer of station 1) + gGeoMan->GetVolume(geoVersion)->AddNode(trd_1, 1); + if (ShowLayer[4]) // if geometry contains layer 5 (1st layer of station 2) + gGeoMan->GetVolume(geoVersion)->AddNode(trd_2, 2); + if (ShowLayer[8]) // if geometry contains layer 9 (1st layer of station 3) + gGeoMan->GetVolume(geoVersion)->AddNode(trd_3, 3); +} diff --git a/reco/detectors/trd/CMakeLists.txt b/reco/detectors/trd/CMakeLists.txt index f967f9fe37c184486242b7686d28cc242d3fe63c..99b31a43fbdefc4e101eb59c65bdacf66da9e9f8 100644 --- a/reco/detectors/trd/CMakeLists.txt +++ b/reco/detectors/trd/CMakeLists.txt @@ -52,6 +52,7 @@ CbmTrdHitProducer.cxx CbmTrdModuleRec.cxx CbmTrdModuleRecR.cxx CbmTrdModuleRecT.cxx +CbmTrdDigiRec.cxx unpack/CbmTrdUnpackConfig.cxx unpack/CbmTrdUnpackAlgoBaseR.cxx diff --git a/reco/detectors/trd/CbmTrdDigiRec.cxx b/reco/detectors/trd/CbmTrdDigiRec.cxx new file mode 100644 index 0000000000000000000000000000000000000000..87b169484f348bc966bbe665b4d9d81065216d62 --- /dev/null +++ b/reco/detectors/trd/CbmTrdDigiRec.cxx @@ -0,0 +1,118 @@ +/* Copyright (C) 2018-2020 Horia Hulubei National Institute of Physics and Nuclear Engineering, Bucharest + SPDX-License-Identifier: GPL-3.0-only + Authors: Alexandru Bercuci[committer] */ + +#include "CbmTrdDigiRec.h" + +#include "CbmTrdFASP.h" + +ClassImp(CbmTrdDigiRec) + + //_____________________________________________________________________________ + CbmTrdDigiRec::CbmTrdDigiRec() + : CbmTrdDigi() + , fStatus(0) +{ + fG[0] = 1.; + fG[1] = 1.; + memset(fT, 0, 3 * sizeof(Double_t)); +} + +//_____________________________________________________________________________ +CbmTrdDigiRec::CbmTrdDigiRec(const CbmTrdDigi& d, Double_t* G, Double_t* T) : CbmTrdDigi(d), fStatus(0) +{ + if (G) { + fG[0] = G[0]; + fG[1] = G[1]; + } + else { + fG[0] = 1.; + fG[1] = 1.; + } + if (T) memcpy(fT, T, 3 * sizeof(Double_t)); + else + memset(fT, 0, 3 * sizeof(Double_t)); + + Int_t dt; + Double_t t, r = CbmTrdDigi::GetCharge(t, dt); + if (t > 4094) SETBIT(fStatus, 0); + if (r > 4094) SETBIT(fStatus, 1); +} + +//_____________________________________________________________________________ +CbmTrdDigiRec::CbmTrdDigiRec(const CbmTrdDigi& d, const CbmTrdDigi& dr, Double_t* G, Double_t* T) + : CbmTrdDigi(d) + , fStatus(0) +{ + /** Constructor and RAW digi merger +*/ + if (G) { + fG[0] = G[0]; + fG[1] = G[1]; + } + else { + fG[0] = 1.; + fG[1] = 1.; + } + if (T) memcpy(fT, T, 3 * sizeof(Double_t)); + else + memset(fT, 0, 3 * sizeof(Double_t)); + + Int_t dt; + Double_t t, r = dr.GetCharge(t, dt); + if (r > 4094) SETBIT(fStatus, 1); + CbmTrdDigi::GetCharge(t, dt); + if (t > 4094) SETBIT(fStatus, 0); + dt = dr.GetTimeDAQ() - GetTimeDAQ(); + SetCharge(t, r, dt); + Int_t rtrg(dr.GetTriggerType() & 2), ttrg(GetTriggerType() & 1); + SetTriggerType(rtrg | ttrg); //merge the triggers +} + +//_____________________________________________________________________________ +Double_t CbmTrdDigiRec::GetCharge(Int_t typ, Bool_t& on) const +{ + Int_t dT; + Double_t T, R = CbmTrdDigi::GetCharge(T, dT); + on = kTRUE; + if (typ) { // rectangular pairing + if (R > 0) { + R -= CbmTrdFASP::GetBaselineCorr(); + return fG[1] * R; + } + else + on = kFALSE; + } + else { // tilt pairing + if (T > 0) { + T -= CbmTrdFASP::GetBaselineCorr(); + return fG[0] * T; + } + else + on = kFALSE; + } + return 0.; +} + +//_____________________________________________________________________________ +Double_t CbmTrdDigiRec::GetTime(Int_t typ) const +{ + Int_t dT; + Double_t T, R = CbmTrdDigi::GetCharge(T, dT); + if (typ) { // rectangular pairing + Double_t R0 = R - fT[2]; + return GetTimeDAQ() + dT + fT[0] * R0 * R0 + fT[1] * R0; + } + else { // tilt pairing + Double_t T0 = T - fT[2]; + return GetTimeDAQ() + fT[0] * T0 * T0 + fT[1] * T0; + } +} + +//_____________________________________________________________________________ +void CbmTrdDigiRec::Init(Double_t g[2], Double_t t[3]) +{ + fG[0] = g[0]; + fG[1] = g[1]; + memcpy(fT, t, 3 * sizeof(Double_t)); +} diff --git a/reco/detectors/trd/CbmTrdDigiRec.h b/reco/detectors/trd/CbmTrdDigiRec.h new file mode 100644 index 0000000000000000000000000000000000000000..65420d4d80de5002c4e21f31ffe55f369f6afa05 --- /dev/null +++ b/reco/detectors/trd/CbmTrdDigiRec.h @@ -0,0 +1,67 @@ +/* Copyright (C) 2018-2020 Horia Hulubei National Institute of Physics and Nuclear Engineering, Bucharest + SPDX-License-Identifier: GPL-3.0-only + Authors: Alexandru Bercuci[committer] */ + +#ifndef CBMTRDDIGIREC_H +#define CBMTRDDIGIREC_H + +#include "CbmTrdDigi.h" + +/** @class CbmTrdDigiRec + ** @brief Extend the TRD(2D) digi class to incorporate FEE calibration. + ** @author Alexandru Bercucic <abercuci@niham.nipne.ro> + ** @since 01.10.2021 + ** @date 01.10.2021 + ** + ** The digi class contains the information as it is produced by the FEE (ASIC/GETS) + ** The variation from channel to channel is captured by running the pulser on anode wires + ** using various signal values, frequencies, etc. The calibrated baselines, gains, jitter, + ** etc. are transported via the parameter files and are applied to the data within the digRec + ** class which is in the end used to calculate the TRD hit parameters. + **/ +class CbmTrdDigiRec : public CbmTrdDigi { + friend class CbmTrdModuleRecT; + +public: + /** \brief Default constructor*/ + CbmTrdDigiRec(); + /** \brief Wrap CbmTrdDigi constructor*/ + CbmTrdDigiRec(const CbmTrdDigi& d, Double_t* g = NULL, Double_t* t = NULL); + virtual ~CbmTrdDigiRec() { ; } + + /** \brief Return calibrated tilt signal + * \param[out] on flag signal exists */ + Double_t GetTiltCharge(Bool_t& on) const { return GetCharge(0, on); } + /** \brief Return calibrated tilt time [ns]*/ + Double_t GetTiltTime() const { return GetTime(0); } + /** \brief Return calibrated rect signal + * \param[out] on flag signal exists */ + Double_t GetRectCharge(Bool_t& on) const { return GetCharge(1, on); } + /** \brief Return calibrated rect time [ns]*/ + Double_t GetRectTime() const { return GetTime(1); } + /** \brief Return calibrated signal + * \param[in] typ tilt [0], rect [1] + * \param[out] on flag signal exists + */ + Double_t GetCharge(Int_t typ, Bool_t& on) const; + /** \brief Return calibrated time + * \param[in] typ tilt [0], rect [1] + */ + Double_t GetTime(Int_t typ) const; + Bool_t HasRectOvf() const { return TESTBIT(fStatus, 1); } + Bool_t HasTiltOvf() const { return TESTBIT(fStatus, 0); } + /** \brief Init FEE gain and time walk corrections */ + void Init(Double_t g[2], Double_t t[3]); + +protected: + /** \brief Constructor and merger*/ + CbmTrdDigiRec(const CbmTrdDigi& dt, const CbmTrdDigi& dr, Double_t* g = NULL, Double_t* t = NULL); + +private: + UChar_t fStatus; //< bit map to store calibration flags + Double_t fG[2]; //< FEE gain correction for channel T & R + Double_t fT[3]; //< FEE time walk correction as function of charge + ClassDef(CbmTrdDigiRec, 1); // Wrapper around the RAW TRD digi (CbmTrdDigi) to acount for calibration +}; + +#endif diff --git a/reco/detectors/trd/CbmTrdHitProducer.cxx b/reco/detectors/trd/CbmTrdHitProducer.cxx index 904d9d3177c536b07e97205791ed2b20b4938654..16e554833bd6e256a671294bb0adbb31c01a2e58 100644 --- a/reco/detectors/trd/CbmTrdHitProducer.cxx +++ b/reco/detectors/trd/CbmTrdHitProducer.cxx @@ -80,11 +80,19 @@ void CbmTrdHitProducer::addModuleHits(CbmTrdModuleRec* mod, Int_t* hitCounter, C //____________________________________________________________________________________ CbmTrdModuleRec* CbmTrdHitProducer::AddModule(Int_t address, TGeoPhysicalNode* node) { - TString s(node->GetName()); - Int_t typ = TString(s[s.Index("module") + 6]).Atoi(); + CbmTrdGeoHandler geoHandler; + Int_t moduleAddress = geoHandler.GetModuleAddress(node->GetName()), + moduleType = geoHandler.GetModuleType(node->GetName()), lyId = CbmTrdAddress::GetLayerId(address); + if (moduleAddress != address) { + LOG(error) << "CbmTrdHitProducer::AddModule: Module ID " << address << " does not match geometry definition " + << moduleAddress << ". Module init failed!"; + return NULL; + } + LOG(debug) << GetName() << "::AddModule(" << node->GetName() << " " << (moduleType < 9 ? 'R' : 'T') << "] mod[" + << moduleAddress << "] ly[" << lyId << "] det[" << moduleAddress << "]"; CbmTrdModuleRec* module(NULL); - if (typ == 9) { module = fModules[address] = new CbmTrdModuleRecT(address); } + if (moduleType >= 9) { module = fModules[address] = new CbmTrdModuleRecT(address); } else { module = fModules[address] = new CbmTrdModuleRecR(address); } @@ -125,7 +133,7 @@ CbmTrdModuleRec* CbmTrdHitProducer::AddModule(Int_t address, TGeoPhysicalNode* n module->SetChmbPar(pChmb); // try to load Gain parameters for module - if (typ == 9) { + if (moduleType >= 9) { const CbmTrdParModGain* pGain(NULL); if (!fGainPar || !(pGain = (const CbmTrdParModGain*) fGainPar->GetModulePar(address))) { //LOG(warn) << GetName() << "::AddModule : No Gain params for modAddress "<< address <<". Using default."; @@ -187,6 +195,7 @@ void CbmTrdHitProducer::processCluster(const Int_t clusterIdx) auto mod = imod->second; std::vector<const CbmTrdDigi*> digivec = {}; + // get digis for current cluster for (Int_t iDigi = 0; iDigi < cluster->GetNofDigis(); iDigi++) { const CbmTrdDigi* digi = CbmDigiManager::Instance()->Get<CbmTrdDigi>(cluster->GetDigi(iDigi)); @@ -194,7 +203,6 @@ void CbmTrdHitProducer::processCluster(const Int_t clusterIdx) if (digi->GetType() == CbmTrdDigi::eCbmTrdAsicType::kSPADIC && digi->GetCharge() <= 0) continue; digivec.emplace_back(digi); } - mod->MakeHit(clusterIdx, cluster, &digivec); fNrClusters++; @@ -207,7 +215,8 @@ Int_t CbmTrdHitProducer::addHits(CbmEvent* event) for (std::map<Int_t, CbmTrdModuleRec*>::iterator imod = fModules.begin(); imod != fModules.end(); imod++) { auto mod = imod->second; - mod->Finalize(); + mod->PreProcessHits(); + mod->PostProcessHits(); addModuleHits(mod, &hitCounter, event); } diff --git a/reco/detectors/trd/CbmTrdModuleRec.h b/reco/detectors/trd/CbmTrdModuleRec.h index 6cac03d54c26f14153446f6c022638b5de64d556..93dbc1c2e81432041fedd476e3ebab1c513907cb 100644 --- a/reco/detectors/trd/CbmTrdModuleRec.h +++ b/reco/detectors/trd/CbmTrdModuleRec.h @@ -38,10 +38,10 @@ public: * \brief Clear local storage **/ virtual void Clear(Option_t* opt = ""); - /** - * \brief Reconstruct physics observables on hits - **/ - virtual Bool_t Finalize() { return kTRUE; } + /** \brief Hit quality assesment */ + virtual Bool_t PreProcessHits() { return kTRUE; } + /** \brief Hit quality assesment */ + virtual Bool_t PostProcessHits() { return kTRUE; } /** * \brief Steering routine for finding digits clusters **/ diff --git a/reco/detectors/trd/CbmTrdModuleRecT.cxx b/reco/detectors/trd/CbmTrdModuleRecT.cxx index f320f8a8afdc10387cc94dab9706ad6947bfee4a..fbeea5ce7a27ac4ebcbdecc5fbaa4ea6e5bca15e 100644 --- a/reco/detectors/trd/CbmTrdModuleRecT.cxx +++ b/reco/detectors/trd/CbmTrdModuleRecT.cxx @@ -4,13 +4,15 @@ #include "CbmTrdModuleRecT.h" +#include "CbmDigiManager.h" #include "CbmTrdCluster.h" #include "CbmTrdDigi.h" +#include "CbmTrdDigiRec.h" #include "CbmTrdFASP.h" #include "CbmTrdHit.h" #include "CbmTrdParModDigi.h" -#include <Logger.h> +#include <FairLogger.h> #include <TClonesArray.h> #include <TF1.h> @@ -34,6 +36,12 @@ CbmTrdModuleRecT::CbmTrdModuleRecT() , fConfigMap(0) , fT0(0) , fBuffer() + , fDigis() + , vt0(0) + , vcM(0) + , vrM(0) + , viM(0) + , vyM(0) , vs() , vse() , vt() @@ -48,13 +56,19 @@ CbmTrdModuleRecT::CbmTrdModuleRecT(Int_t mod, Int_t ly, Int_t rot) , fConfigMap(0) , fT0(0) , fBuffer() + , fDigis() + , vt0(0) + , vcM(0) + , vrM(0) + , viM(0) + , vyM(0) , vs() , vse() , vt() , vx() , vxe() { - //printf("AddModuleT @ %d\n", mod); Config(1,0); + // printf("AddModuleT @ %d\n", mod); Config(1,0); SetNameTitle(Form("TrdRecT%d", mod), "Reconstructor for triangular read-out."); } @@ -64,7 +78,7 @@ CbmTrdModuleRecT::~CbmTrdModuleRecT() {} //_______________________________________________________________________________ Bool_t CbmTrdModuleRecT::AddDigi(const CbmTrdDigi* d, Int_t id) { - /* Add digi to cluster fragments. At first clusters are ordered on pad rows and time. + /** Add digi to cluster fragments. At first clusters are ordered on pad rows and time. * No channel ordering is assumed. The time condition for a digi to enter a cluster * chunk is to have abs(dt)<5 wrt cluster t0 */ @@ -197,32 +211,562 @@ Int_t CbmTrdModuleRecT::FindClusters() Bool_t CbmTrdModuleRecT::MakeHits() { return kTRUE; } //_______________________________________________________________________________ -Bool_t CbmTrdModuleRecT::Finalize() +Bool_t CbmTrdModuleRecT::PreProcessHits() { - /* Steering routine for classifying hits and apply further analysis + /** Steering routine for classifying hits and apply further analysis * -> hit deconvolution (see Deconvolute) + */ + + Int_t nhits = fHits->GetEntriesFast(); + if (CWRITE()) LOG(info) << "\n" << GetName() << "::PreProcessHits(" << nhits << ")"; + + CbmTrdHit* hit(NULL); + for (Int_t ih(0); ih < nhits; ih++) { + hit = (CbmTrdHit*) ((*fHits)[ih]); + if (!CheckConvolution(hit)) continue; + nhits += Deconvolute(hit); + } + nhits = fHits->GetEntriesFast(); + if (CWRITE()) LOG(info) << "\n" << GetName() << "::Deconvolute(" << nhits << ")"; + return kTRUE; +} + +//_______________________________________________________________________________ +Bool_t CbmTrdModuleRecT::CheckConvolution(CbmTrdHit* /*h*/) const { return kFALSE; } + +//_______________________________________________________________________________ +Bool_t CbmTrdModuleRecT::Deconvolute(CbmTrdHit* /*h*/) { return kFALSE; } + +//_______________________________________________________________________________ +Bool_t CbmTrdModuleRecT::PostProcessHits() +{ + /** Steering routine for classifying hits and apply further analysis * -> hit merging for row-cross (see RowCross) */ - // Int_t nhits=fHits->GetEntriesFast(); - // //if(CWRITE()) - // LOG(info) << "\n"<<GetName()<<"::Finalize("<<nhits<<")"; - // CbmTrdHit *hit(NULL), *hitp(NULL); - // for(Int_t ih(0); ih<nhits; ih++){ - // hit = (CbmTrdHit*)((*fHits)[ih]); - // for(Int_t jh(ih+1); jh<nhits; jh++){ - // hitp = (CbmTrdHit*)((*fHits)[jh]); - // //if(CWRITE()) - // cout<<ih<<" "<<hit->ToString(); - // cout<<"-> "<<jh<<" "<<hitp->ToString(); - // } - // } + CbmTrdHit *h0(NULL), *h1(NULL); + + Int_t a0, nhits = fHits->GetEntriesFast(); + Float_t Dx(2 * fDigiPar->GetPadSizeX(0)), Dy(2 * fDigiPar->GetPadSizeY(0)); + for (Int_t ih(0); ih < nhits; ih++) { + h0 = (CbmTrdHit*) ((*fHits)[ih]); + if (h0->IsUsed()) continue; + + for (Int_t jh(ih + 1); jh < nhits; jh++) { + h1 = (CbmTrdHit*) ((*fHits)[jh]); + if (h1->IsUsed()) continue; + + // basic check on Row + if (TMath::Abs(h1->GetY() - h0->GetY()) > Dy) continue; + + // basic check on Col + if (TMath::Abs(h1->GetX() - h0->GetX()) > Dx) continue; + + // basic check on Time + if (TMath::Abs(h1->GetTime() - h0->GetTime()) > 4000) continue; // TODO check with preoper time calibration + + // go to topologic checks + if (!(a0 = CheckMerge(h0->GetRefId(), h1->GetRefId()))) continue; + + ProjectDigis(a0 < 0 ? h0->GetRefId() : h1->GetRefId(), a0 < 0 ? h1->GetRefId() : h0->GetRefId()); + + // call the working algorithm + if (MergeHits(h0, a0)) h0->SetRowCross(h1); + if (CWRITE()) { + cout << ih << " : " << h0->ToString(); + cout << jh << " : " << h1->ToString(); + cout << "\n" << endl; + } + } + } + nhits = 0; + for (Int_t ih(0); ih < fHits->GetEntriesFast(); ih++) { + h0 = (CbmTrdHit*) ((*fHits)[ih]); + if (!h0->IsUsed()) continue; + fHits->RemoveAt(ih); //delete h0; + nhits++; + } + fHits->Compress(); + + // clear all calibrated digis + for (map<Int_t, vector<CbmTrdDigiRec*>>::iterator ic = fDigis.begin(); ic != fDigis.end(); ic++) { + for (vector<CbmTrdDigiRec*>::iterator id = ic->second.begin(); id != ic->second.end(); id++) + delete *id; + ic->second.clear(); + } + fDigis.clear(); + + if (CWRITE()) LOG(info) << "\n" << GetName() << "::MergeHits(" << nhits << ")"; + return kTRUE; +} + + +//_______________________________________________________________________________ +Int_t CbmTrdModuleRecT::CheckMerge(Int_t cid, Int_t cjd) +{ + /** Check topologic conditions if the 2 clusters (in digi representation) can be merged. + * The first pair is always from the bottom row + * return the anode candidate wrt boundary 1, 2, 3 for the first 3 anodes of the upper row; -1, -2, -3 for the bottom row (r0) or 0 if the check fails + */ + + Bool_t on(kFALSE); + Int_t /*row, */ col, rowMax(0), vc[2] = {-1, -1}, vm[2] = {0}, vcid[2] = {cid, cjd}; + Double_t t(0.), r(0.), rtMax(0.), T(0.), m, d, mdMax(0.), M[2] = {-1., -1.}, S[2] = {0.}; + vector<CbmTrdDigiRec*>::iterator id, jd, jp[2]; + for (Int_t rowId(0); rowId < 2; rowId++) { + rtMax = 0.; + mdMax = 0.; + for (id = fDigis[vcid[rowId]].begin(); id != fDigis[vcid[rowId]].end(); id++) { + GetPadRowCol((*id)->GetAddressChannel(), col); + //cout<<(*id)->ToString(); + + // mark max position and type + t = (*id)->GetTiltCharge(on); + if (on && t > rtMax) { + vc[rowId] = col; + vm[rowId] = 0; + rtMax = t; + } + r = (*id)->GetRectCharge(on); + if (on && r > rtMax) { + vc[rowId] = col; + vm[rowId] = 1; + rtMax = r; + } + + m = 0.; + d = 0.; + if (!rowId) { // compute TR pairs on the bottom row + m = 0.5 * (t + r); + d = r - t; + } + else { // compute RT pairs on the upper row + jd = id + 1; + T = 0.; + if (jd != fDigis[vcid[rowId]].end()) T = (*jd)->GetTiltCharge(on); + + m = 0.5 * (r + T); + d = r - T; + } + if (TMath::Abs(m) > 0.) d = 1.e2 * d / m; + if (m > mdMax) { + mdMax = m; + M[rowId] = m; + S[rowId] = d; + jp[rowId] = id; + rowMax = rowId; + } + } + } + rowMax = M[0] > M[1] ? 0 : 1; + + // basic check on col of the max signal + Int_t dc = vc[1] - vc[0]; + if (dc < 0 || dc > 1) return 0; + + // special care for both tilt maxima : the TT case + // recalculate values on the min row on neighbor column + if (!vm[0] && !vm[1]) { + if (rowMax == 0) { // modify r=1 + r = T = 0.; + if (M[1] >= 0) { + if (jp[1] != fDigis[cjd].end()) jp[1]++; + if (jp[1] != fDigis[cjd].end()) { + r = (*jp[1])->GetRectCharge(on); + jp[1]++; + if (jp[1] != fDigis[cjd].end()) T = (*jp[1])->GetTiltCharge(on); + } + } + M[1] = 0.5 * (r + T); + S[1] = r - T; + } + else { // modify r=0 + r = t = 0.; + if (M[0] >= 0) { + if (jp[0] != fDigis[cid].begin()) jp[0]--; + if (jp[0] != fDigis[cid].begin()) { + r = (*jp[0])->GetRectCharge(on); + t = (*jp[0])->GetTiltCharge(on); + } + } + M[0] = 0.5 * (t + r); + S[0] = r - t; + } + } + rowMax = M[0] > M[1] ? 0 : 1; + + // Build the ratio of the charge + Float_t mM = M[rowMax ? 0 : 1] / M[rowMax]; + + // Float_t mM_c[] = {0.03, 0.243, 0.975}, // center of distribution for each anode hypo + // mM_s[] = {0., 1.7e-3, 8.8e-3}, // slope of distribution for each anode hypo + // mM_r[] = {0.03, 0.03, 0.01}; // range of distribution for each anode hypo in proper coordinates + // for(Int_t ia(0); ia<3; ia++) + // if(TMath::Abs(mM_s[ia] * S[rowMax] + mM_c[ia] - mM) < mM_r[ia] ) return (rowMax?1:-1) * (3-ia); + + Float_t mS = TMath::Abs(S[rowMax]), mM_l[3] = {0.15, 0.5, 1}, mM_r[3] = {0, 0.28, 1}, mS_r[3] = {43, 27, 20}, dSdM[2], + S0[2]; + for (Int_t i(0); i < 2; i++) { + dSdM[i] = (mS_r[i + 1] - mS_r[i]) / (mM_r[i + 1] - mM_r[i]); + S0[i] = mS_r[i] - dSdM[i] * mM_r[i]; + } + Int_t irange = mM < mM_r[1] ? 0 : 1; + if (mS > S0[irange] + dSdM[irange] * mM) return 0; + + for (Int_t ia(0); ia < 3; ia++) { + if (mM < mM_l[ia]) return (rowMax ? 1 : -1) * (3 - ia); + } + return 0; +} + + +//_______________________________________________________________________________ +Bool_t CbmTrdModuleRecT::MergeHits(CbmTrdHit* h, Int_t a0) +{ + Int_t n0(vs.size() - 2); + Double_t dx(0.), dy(0.); + + switch (n0) { + case 1: + if (IsMaxTilt()) { // T + dx = -0.5; + dy = 0; + } + else { // R + dx = 0.5; + dy = 0; + } + break; + case 2: + if (IsOpenLeft() && IsOpenRight()) { // RT + dx = viM == 1 ? 0. : -1; + dy = -0.5; + } + else { // TR + dx = 0.; + dy = 0.5; + } + break; + case 3: + if (IsMaxTilt() && !IsSymmHit()) { // TRT asymm + dx = viM == 1 ? 0. : -1; + dy = GetYoffset(); + } + else if (!IsMaxTilt() && IsSymmHit()) { // TRT symm + dx = 0.; + dy = GetYoffset(); + } + else if (IsMaxTilt() && IsSymmHit()) { // RTR symm + dx = GetXoffset(); + dy = 0.; + } + else if (!IsMaxTilt() && !IsSymmHit()) { // RTR asymm + dx = GetXoffset(); + dy = viM == 1 ? -0.5 : 0.5; + } + break; + default: + dx = GetXoffset(); + dy = GetYoffset(); + break; + } + + RecenterXoffset(dx); + Int_t typ(GetHitClass()); + // get position correction [pw] + Double_t xcorr = GetXcorr(dx, typ, 1) / fDigiPar->GetPadSizeX(0), xcorrBias(xcorr); + if (IsBiasX()) { + typ = GetHitRcClass(a0); + Int_t xmap = vyM & 0xff; + switch (n0) { + case 4: + if (dx < 0) xcorrBias += (IsBiasXleft() ? -0.12 : 0.176); + else + xcorrBias += (xmap == 53 || xmap == 80 || xmap == 113 || xmap == 117 ? -0.176 : 0.12); + break; + case 5: + case 7: + if (typ < 0) break; + if (xmap == 50 || xmap == 58 || xmap == 146 || xmap == 154) { + if (typ == 2) xcorr += 0.0813; + else if (typ == 3) { + xcorr -= 0.0813; + typ = 2; + } + dx -= xcorr; + RecenterXoffset(dx); + xcorrBias = GetXcorr(dx, typ, 2) / fDigiPar->GetPadSizeX(0); + } + else { + dx -= xcorr; + RecenterXoffset(dx); + if (typ < 2) xcorrBias = GetXcorr(dx, typ, 2) / fDigiPar->GetPadSizeX(0); + else if (typ == 2) + xcorrBias = 0.12; + else if (typ == 3) + xcorrBias = -0.12; + } + break; + default: + if (typ < 0) break; + else if (typ == 2) + xcorr += 0.0813; + else if (typ == 3) { + xcorr -= 0.0813; + typ = 2; + } + dx -= xcorr; + RecenterXoffset(dx); + xcorrBias = GetXcorr(dx, typ, 2) / fDigiPar->GetPadSizeX(0); + break; + } + } + else { + if (typ) xcorrBias += (dx < 0 ? 1 : -1) * 0.0293; + } + dx -= xcorrBias; + RecenterXoffset(dx); + dy = dx - dy; + RecenterYoffset(dy); + if (dy < -0.5 || dy > 0.5) printf("!!! dy = %f r[%d]\n", dy, vrM); + + Double_t ycorr = GetYcorr(dy) / fDigiPar->GetPadSizeY(0); + dy += ycorr; + RecenterYoffset(dy); + dx *= fDigiPar->GetPadSizeX(0); + dy *= fDigiPar->GetPadSizeY(0); + + TVector3 local_pad, local_pad_err; + Int_t srow, sector = fDigiPar->GetSectorRow(vrM, srow); + fDigiPar->GetPadPosition(sector, vcM, srow, local_pad, local_pad_err); + + Double_t edx(1), edy(1), edt(60), time(-21), tdrift(100), e(200); + Double_t local[3] = {local_pad[0] + dx, local_pad[1] + dy, local_pad[2]}, global[3]; + // globalErr[3] = {0/*edx*/, 0/*edy*/, 0.}; + LocalToMaster(local, global); + h->SetX(global[0]); + h->SetY(global[1]); + h->SetZ(global[2]); + h->SetDx(edx); + h->SetDy(edy); + h->SetDz(0.); + h->SetDxy(0.); + h->SetTime(CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kFASP) * (vt0 + time) - tdrift + 30.29, edt); + h->SetELoss(e); + // hit->SetClassType(); + // hit->SetMaxType(tM); + // if(ovf) hit->SetOverFlow(); + + if (CWRITE()) { + printf("-> loc[%6.2f %6.2f %6.2f] err[%6.2f %6.2f %6.2f]\n", local_pad[0], local_pad[1], local_pad[2], + local_pad_err[0], local_pad_err[1], local_pad_err[2]); + printf("REC col[%2d] row[%2d] dx[%7.3f(pw) %7.3f(cm)] x[%7.2f] y[%7.2f] dy[%5.2f] t0[%llu]\n", vcM, vrM, + dx / fDigiPar->GetPadSizeX(0), dx, global[0], global[1], dy, vt0); + } + + return kTRUE; +} + +//_______________________________________________________________________________ +Bool_t CbmTrdModuleRecT::BuildHit(CbmTrdHit* h) +{ + Int_t n0(vs.size() - 2); + Double_t dx(0.), dy(0.); //, da(0.); + + switch (n0) { + case 1: + if (IsMaxTilt()) { // T + dx = -0.5; + dy = 0; + } + else { // R + dx = 0.5; + dy = 0; + } + break; + case 2: + if (IsOpenLeft() && IsOpenRight()) { // RT + dx = viM == 1 ? 0. : -1; + dy = -0.5; + } + else { // TR + dx = 0.; + dy = 0.5; + } + break; + case 3: + if (IsMaxTilt() && !IsSymmHit()) { // TRT asymm + dx = viM == 1 ? 0. : -1; + dy = GetYoffset(); + } + else if (!IsMaxTilt() && IsSymmHit()) { // TRT symm + dx = 0.; + dy = GetYoffset(); + } + else if (IsMaxTilt() && IsSymmHit()) { // RTR symm + dx = GetXoffset(); + dy = 0.; + } + else if (!IsMaxTilt() && !IsSymmHit()) { // RTR asymm + dx = GetXoffset(); + dy = viM == 1 ? -0.5 : 0.5; + } + break; + default: + dx = GetXoffset(); + dy = GetYoffset(); + break; + } + RecenterXoffset(dx); + + // get position correction + Double_t xcorr = GetXcorr(dx, GetHitClass()) / fDigiPar->GetPadSizeX(0); + dx -= xcorr; + RecenterXoffset(dx); + dy = dx - dy; + RecenterYoffset(dy); + if (dy < -0.5 || dy > 0.5) printf("!!! dy = %f r[%d]\n", dy, vrM); + + Double_t ycorr = GetYcorr(dy) / fDigiPar->GetPadSizeY(0); + dy += ycorr; + RecenterYoffset(dy); + dx *= fDigiPar->GetPadSizeX(0); + dy *= fDigiPar->GetPadSizeY(0); + + // get anode wire offset + Int_t ia(0); + Float_t ya(0.); // anode position in local pad coordinates + for (; ia <= NANODE; ia++) { + ya = -1.35 + ia * 0.3; + if (dy > ya + 0.15) continue; + break; + } + // da = dy-ya; + // //correct inside apmlification region + // da*=-0.7; + // if(da<-0.015) da+=0.1; + // else if(da>0.015) da-=0.1; + // dy+=da; + // da = dy - ya; + + // Error parametrization X : parabolic model on cl size + Double_t parX[] = {0.713724, -0.318667, 0.0366036}; + Double_t parY[] = {0.0886413, 0., 0.0435141}; + Int_t nex = TMath::Min(n0, 7); + Double_t edx = parX[0] + parX[1] * nex + parX[2] * nex * nex, edy = parY[0] + parY[2] * dy * dy, + edt = 26.33; // should be parametrized as function of da TODO + // use this trick to force larger roads on CbmLitTrackFinderBranch + // target code from CbmLitTrackFinderBranch::FollowTracks and CbmLitHitData::AddHit + // bool hitInside = (pixelHit->GetX() < (tpar.GetX() + devX)) && (pixelHit->GetX() > (tpar.GetX() - devX)) + if (n0 < 3) { + edx = 1.; + edy = 1.; + edt = 60.; + } + + TVector3 local_pad, local_pad_err; + Int_t srow, sector = fDigiPar->GetSectorRow(vrM, srow); + fDigiPar->GetPadPosition(sector, vcM, srow, local_pad, local_pad_err); + + Double_t local[3] = {local_pad[0] + dx, local_pad[1] + dy, local_pad[2]}, global[3]; + //globalErr[3] = {edx, edy, 0.}; + LocalToMaster(local, global); + + // COMPUTE TIME + for (Int_t idx(1); idx <= n0; idx++) { + Double_t dtFEE = + fgDT[0] * (vs[idx] - fgDT[1]) * (vs[idx] - fgDT[1]) / CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kFASP); + if (vxe[idx] > 0) vx[idx] += dy / fDigiPar->GetPadSizeY(0); + fgT->SetPoint(idx - 1, vx[idx], vt[idx] - dtFEE); + } + Double_t xc = vx[n0 + 2]; + for (Int_t ip(n0); ip < fgT->GetN(); ip++) { + fgT->SetPoint(ip, xc, 0); + xc += 0.5; + } + Double_t time(-21.), tdrift(100); // should depend on Ua + if (n0 > 1 && (fgT->Fit("pol1", "QC", "goff") == 0)) { + TF1* f = fgT->GetFunction("pol1"); + time = f->GetParameter(0) - fgDT[2]; + if (TMath::IsNaN(time)) time = -21; + //dtime += TMath::Abs(f->GetParameter(1)*(vx[n0+1] - vx[1])); + } + + // COMPUTE ENERGY + for (UInt_t idx(0); idx < vs.size(); idx++) { + if (vxe[idx] > 0) { + fgEdep->SetPoint(idx, vx[idx] + dy / fDigiPar->GetPadSizeY(0), vs[idx]); + fgEdep->SetPointError(idx, vxe[idx], vse[idx]); + } + else { + fgEdep->SetPoint(idx, vx[idx], vs[idx]); + fgEdep->SetPointError(idx, vxe[idx], vse[idx]); + } + } + xc = vx[n0 + 2]; + for (Int_t ip(vs.size()); ip < fgEdep->GetN(); ip++) { + //fgEdep->RemovePoint(ip); + xc += 0.5; + fgEdep->SetPoint(ip, xc, 0); + fgEdep->SetPointError(ip, 0., 300); + } + //if(CWRITE()) fgEdep->Print(); + + Double_t e(0.), xlo(*vx.begin()), xhi(*vx.rbegin()); + fgPRF->SetParameter(0, vs[viM]); + fgPRF->FixParameter(1, dx / fDigiPar->GetPadSizeX(0)); + fgPRF->SetParameter(2, 0.65); + fgPRF->SetParLimits(2, 0.45, 10.5); + fgEdep->Fit(fgPRF, "QBN", "goff", xlo - 0.5, xhi + 0.5); + if (!fgPRF->GetNDF()) return NULL; + //chi = fgPRF->GetChisquare()/fgPRF->GetNDF(); + e = fgPRF->Integral(xlo - 0.5, xhi + 0.5); + + // apply MC correction + Float_t gain0 = 210.21387; //(XeCO2 @ 1900V) + // Float_t grel[3] = {1., 0.98547803, 0.93164071}, + // goff[3][3] = { + // {0.05714, -0.09, -0.09}, + // {0., -0.14742, -0.14742}, + // {0., -0.29, -0.393} + // }; + // Int_t ian=0; + // if(TMath::Abs(dy)<=0.3) ian=0; + // else if(TMath::Abs(dy)<=0.6) ian=1; + // else if(TMath::Abs(dy)<=0.9) ian=2; + // Int_t isize=0; + // if(n0<=3) isize=0; + // else if(n0<=4) isize=1; + // else isize=2; + Float_t gain = gain0; //*grel[ian]; + e /= gain; // apply effective gain + //e+=goff[ian][isize]; // apply missing energy offset + + h->SetX(global[0]); + h->SetY(global[1]); + h->SetZ(global[2]); + h->SetDx(edx); + h->SetDy(edy); + h->SetDz(0); + h->SetDxy(0.); + h->SetTime(CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kFASP) * (vt0 + time) - tdrift + 30.29, edt); + h->SetELoss(e); + // hit->SetClassType(); + // hit->SetMaxType(tM); + // if(ovf) hit->SetOverFlow(); + + if (CWRITE()) { + printf("-> loc[%6.2f %6.2f %6.2f] err[%6.2f %6.2f %6.2f]\n", local_pad[0], local_pad[1], local_pad[2], + local_pad_err[0], local_pad_err[1], local_pad_err[2]); + printf("REC col[%2d] row[%2d] x[%7.2f] dx[%5.2f] y[%7.2f] dy[%5.2f] t0[%llu]\n", vcM, vrM, global[0], dx, global[1], + dy, vt0); + } + return kTRUE; } #include <TCanvas.h> #include <TH1.h> -#define NANODE 9 //_______________________________________________________________________________ CbmTrdHit* CbmTrdModuleRecT::MakeHit(Int_t ic, const CbmTrdCluster* cl, std::vector<const CbmTrdDigi*>* digis) { @@ -257,191 +801,155 @@ CbmTrdHit* CbmTrdModuleRecT::MakeHit(Int_t ic, const CbmTrdCluster* cl, std::vec } if (CWRITE()) cout << cl->ToString(); + if (!LoadDigis(digis, ic)) return NULL; + if (!ProjectDigis(ic)) return NULL; + Int_t nofHits = fHits->GetEntriesFast(); + CbmTrdHit* hit = new ((*fHits)[nofHits]) CbmTrdHit(); + hit->SetAddress(fModAddress); + hit->SetRefId(ic); + //hit->SetMatch(); + BuildHit(hit); + if (CWRITE()) cout << hit->ToString(); + if (CDRAW()) DrawHit(hit); + return hit; +} - // check cluster integrity and do digi merging if needed - vector<Bool_t> vmask(digis->size(), 0); // masks in case of merged Digis - vector<CbmTrdDigi*> vdgM; - if (cl->GetNCols() != digis->size() && !MergeDigis(digis, &vdgM, &vmask)) { - cout << cl->ToString(); - for (vector<const CbmTrdDigi*>::iterator i = digis->begin(); i != digis->end(); i++) - cout << (*i)->ToString(); - return NULL; - } - - // Read in all digis information() - ULong64_t t0 = fT0 + cl->GetStartTime(); // absolute hit time (prompt signal) - Int_t n0(0), ovf(0), cM; - if (!(n0 = LoadDigis(digis, &vdgM, &vmask, t0, cM))) { - cout << cl->ToString(); - for (vector<const CbmTrdDigi*>::iterator i = digis->begin(); i != digis->end(); i++) - cout << (*i)->ToString(); - return NULL; - } - if (n0 < 0) { - ovf = 1; - n0 *= -1; - } - - // analyse digis topology; no of signal types, maximum, etc - Bool_t tM(kTRUE); // maximum type tilt=1; rect=0 - Int_t nL(0); // signal index for the max signal - Int_t col, row = GetPadRowCol(cl->GetStartCh(), col); - Double_t max(0.), // maximum signal - LS(0.), // left side sum of signals - S(0.); // sum of signals - Int_t nr(0), nt(0); - for (Int_t is(1); is <= n0; is++) { - if (vxe[is] > 0) { // select tilted coupling - nt++; - S += vs[is]; - if (vs[is] > max) { - max = vs[is]; - tM = kTRUE; - nL = is; - LS += vs[is]; - } - } - else { // select rectangular coupling - nr++; - S += vs[is]; - if (vs[is] > max) { - max = vs[is]; - tM = kFALSE; - nL = is; - LS += vs[is]; - } - } - } - col += cM; - S -= LS; - LS -= max; - // evaluate asymmetry - Int_t lr(0), // max signal left-right asymmetry wrt central pad - tr(0), // left-right innequality for symmetric clusters - nR(n0 + 1 - nL); // no of signals to the right of maximum - if (nL < nR) lr = 1; - else if (nL > nR) - lr = -1; - if (!lr && (n0 % 2)) tr = (LS < S ? -1 : 1); - // compute x and y offset from center pad - Double_t dx(0.), dy(0.), edx(0.21650635), - edy(0.77942286); // fixed error parametrization - switch (n0) { - case 1: - if (nt) { - dx = -0.5; - dy = 0; - } // T - else { - dx = 0.5; - dy = 0; - } // R - break; - case 2: - if (cl->HasOpenStart() && cl->HasOpenStop()) { - dx = cM ? -1. : 0.; - dy = -0.5; - } // RT - else { - dx = 0.; - dy = 0.5; - } // TR - break; - case 3: - if (tM && lr) { - dx = cM ? -1. : 0.; - dy = GetYoffset(n0); - } // TRT asymm - else if (!tM && !lr) { - dx = 0.; - dy = GetYoffset(n0); - } // TRT symm - else if (tM && !lr) { - dx = GetXoffset(n0); - dy = 0.; - } // RTR symm - else if (!tM && lr) { - dx = GetXoffset(n0); - dy = cM ? 0.5 : -0.5; - } // RTR asymm - break; - default: - dx = GetXoffset(n0); - dy = GetYoffset(n0); - break; +//_______________________________________________________________________________ +Int_t CbmTrdModuleRecT::GetHitClass() const +{ + /** Incapsulate hit classification criteria based on signal topology + * [0] : center hit type + * [1] : side hit type + */ + + Int_t n0(vs.size() - 2); + if ((n0 == 5 && ((IsMaxTilt() && IsSymmHit()) || (!IsMaxTilt() && !IsSymmHit()))) || // TRTRT symm/asymm + n0 == 4 || (n0 == 3 && ((IsMaxTilt() && IsSymmHit()) || (!IsMaxTilt() && !IsSymmHit())))) + return 1; // RTR symm/asymm + else if (n0 > 5 && HasOvf()) + return 2; + return 0; +} + +//_______________________________________________________________________________ +Int_t CbmTrdModuleRecT::GetHitRcClass(Int_t a0) const +{ + Int_t a0m = TMath::Abs(a0); + UChar_t xmap = vyM & 0xff; + if (a0m == 2 && IsBiasXleft() && IsBiasXright() && !IsBiasXmid()) return 0; + else if (a0m == 3 && ((IsBiasXleft() && IsBiasXright()) || xmap == 116 || xmap == 149 || xmap == 208)) + return 1; + else if (!IsBiasXleft() + && (a0m == 2 + || (a0m == 3 && ((!IsBiasXright() && IsBiasXmid()) || xmap == 209 || xmap == 212 || xmap == 145)))) + return 2; + else if (!IsBiasXright() + && (a0m == 2 || (a0m == 3 && ((!IsBiasXleft() && IsBiasXmid()) || xmap == 112 || xmap == 117)))) + return 3; + else + return -1; +} + +//_______________________________________________________________________________ +Double_t CbmTrdModuleRecT::GetXoffset(Int_t n0) const +{ + Double_t dx(0.), R(0.); + Int_t n(n0 ? n0 : vs.size()); + for (Int_t ir(0); ir < n; ir++) { + if (vxe[ir] > 0) continue; // select rectangular coupling + R += vs[ir]; + dx += vs[ir] * vx[ir]; } - if (dx < -0.5 && cM > 0) { // shift graph representation to fit dx[pw] in [-0.5, 0.5] - dx += 1.; - col -= 1; - for (UInt_t idx(0); idx < vx.size(); idx++) - vx[idx] += 1; - } - if (dx > 0.5) { // dirty fix for compound clusters TODO - Int_t ishift = Int_t(dx - 0.5) + 1; - dx -= ishift; - col += ishift; - for (UInt_t idx(0); idx < vx.size(); idx++) - vx[idx] -= ishift; - } - dy = dx - dy; // only on natural scalling ! - // go to cm scale - dx *= fDigiPar->GetPadSizeX(0); - dy *= fDigiPar->GetPadSizeY(0); + if (TMath::Abs(R) > 0) return dx / R; + LOG(warn) << GetName() << "::GetXoffset : Unexpected null sum."; + return 0.; +} - // apply systematic correction for x (MC derived) - Int_t typ = 0; // [0] center hit type - // [1] side hit type - if ((n0 == 5 && ((tM && !lr) || (!tM && lr))) || // TRTRT symm/asymm - n0 == 4 || (n0 == 3 && ((tM && !lr) || (!tM && lr != 0)))) - typ = 1; // RTR symm/asymm - Double_t xcorr(0.); - Int_t nbins((NBINSCORRX - 1) >> 1), ii = nbins + TMath::Nint(dx / fgCorrXdx), i0, i1; - if (ii < 0 || ii >= NBINSCORRX) - LOG(warn) << GetName() << "::MakeHit : Idx " << ii << " outside range for displacement " << dx << "."; - else { - if (dx < fgCorrXdx * ii) { - i0 = TMath::Max(0, ii - 1); - i1 = ii; - } - else { - i0 = ii; - i1 = TMath::Min(NBINSCORRX - 1, ii + 1); +//_______________________________________________________________________________ +Double_t CbmTrdModuleRecT::GetYoffset(Int_t n0) const +{ + Double_t dy(0.), T(0.); + Int_t n(n0 ? n0 : vs.size()); + for (Int_t it(0); it < n; it++) { + if (vxe[it] > 0) { // select tilted coupling + T += vs[it]; + dy += vs[it] * vx[it]; } - Double_t DDx = (fgCorrXval[typ][i1] - fgCorrXval[typ][i0]), a = DDx / fgCorrXdx, - b = fgCorrXval[typ][i0] - DDx * (i0 - nbins); - xcorr = 0.1 * (b + a * dx); } - dx += xcorr; - dy += xcorr; - if (dx > 0.5 * fDigiPar->GetPadSizeX(0)) dx = 0.5 * fDigiPar->GetPadSizeX(0); - else if (dx < -0.5 * fDigiPar->GetPadSizeX(0)) - dx = -0.5 * fDigiPar->GetPadSizeX(0); + if (TMath::Abs(T) > 0) return dy / T; + LOG(warn) << GetName() << "::GetYoffset : Unexpected null sum."; + return 0.; +} + +//_______________________________________________________________________________ +Double_t CbmTrdModuleRecT::GetXcorr(Double_t dxIn, Int_t typ, Int_t cls) const +{ + /** Give the linear interpolation of SYS correction for current position offset "dx" based + * on LUT calculated wrt MC EbyE data. The position offset is expresed in [pw] units + * while the output is in [cm] + */ + + if (typ < 0 || typ > 2) { + //LOG(error)<< GetName() << "::GetXcorr : type in-param "<<typ<<" out of range."; + return 0; + } + Double_t dx = TMath::Abs(dxIn); + Int_t ii = TMath::Max(0, TMath::Nint(dx / fgCorrXdx) - 1), i0; // i1; - if (dy > 0.5 * fDigiPar->GetPadSizeY(0)) { // - //printf("BEFORE dy[%+6.4f] dx[%+6.4f] {n[%d] max[%c] lr[%+d]}\n", dy, dx, n0, tM?'T':'R', lr); - dy -= fDigiPar->GetPadSizeY(0); + if (ii < 0 || ii > NBINSCORRX) { + LOG(warn) << GetName() << "::GetXcorr : LUT idx " << ii << " out of range for dx=" << dxIn; + return 0; } - if (dy < -0.5 * fDigiPar->GetPadSizeY(0)) { // - //printf("(BEFORE) dy[%+6.4f] dx[%+6.4f] {n[%d] max[%c] lr[%+d]}\n", dy, dx, n0, tM?'T':'R', lr); - dy += fDigiPar->GetPadSizeY(0); + if (dx < fgCorrXdx * ii) { + i0 = TMath::Max(0, ii - 1); + /*i1=ii;*/ + } + else { + i0 = ii; + /*i1=TMath::Min(NBINSCORRX-1,ii+1);*/ } - // process y offset - // apply systematic correction for y (MC derived) + Float_t* xval = &fgCorrXval[typ][i0]; + if (cls == 1) xval = &fgCorrRcXval[typ][i0]; + else if (cls == 2) + xval = &fgCorrRcXbiasXval[typ][i0]; + Double_t DDx = (xval[1] - xval[0]), a = DDx / fgCorrXdx, b = xval[0] - DDx * (i0 + 0.5); + return (dxIn > 0 ? 1 : -1) * b + a * dxIn; +} + +//_______________________________________________________________________________ +Double_t CbmTrdModuleRecT::GetYcorr(Double_t dy, Int_t /* cls*/) const +{ + /** Process y offset. Apply systematic correction for y (MC derived). + * The position offset is expresed in [pw] units while the output is in [cm] + */ Float_t fdy(1.), yoff(0.); + Int_t n0(vs.size() - 2); switch (n0) { case 3: fdy = fgCorrYval[0][0]; yoff = fgCorrYval[0][1]; - if (tM && !lr) dy -= tr * 0.5 * fDigiPar->GetPadSizeY(0); - else if (lr) - dy -= 0.5 * fDigiPar->GetPadSizeY(0); - ; + if (IsMaxTilt() && IsSymmHit()) { + fdy = 0.; + yoff = (dy > 0 ? -1 : 1) * 1.56; + } + else if (!IsMaxTilt() && !IsSymmHit()) { + fdy = 0.; + yoff = (dy > 0 ? -1 : 1) * 1.06; + } + else if (!IsMaxTilt() && IsSymmHit()) { + fdy = 2.114532; + yoff = -0.263; + } + else /*if(IsMaxTilt()&&!IsSymmHit())*/ { + fdy = 2.8016010; + yoff = -1.38391; + } break; case 4: fdy = fgCorrYval[1][0]; yoff = fgCorrYval[1][1]; - if ((!tM && lr == 1) || (tM && lr == -1)) yoff *= -1; + if ((!IsMaxTilt() && IsLeftHit()) || (IsMaxTilt() && !IsLeftHit())) yoff *= -1; break; case 5: case 7: @@ -455,195 +963,361 @@ CbmTrdHit* CbmTrdModuleRecT::MakeHit(Int_t ic, const CbmTrdCluster* cl, std::vec case 10: fdy = fgCorrYval[3][0]; yoff = fgCorrYval[3][1]; - if ((!tM && lr == 1) || (tM && lr == -1)) yoff *= -1; + if ((!IsMaxTilt() && IsLeftHit()) || (IsMaxTilt() && !IsLeftHit())) yoff *= -1; break; } - dy *= fdy; - dy += yoff; - if (dy > 0.5 * fDigiPar->GetPadSizeY(0)) dy = 0.5 * fDigiPar->GetPadSizeY(0); - else if (dy < -0.5 * fDigiPar->GetPadSizeY(0)) - dy = -0.5 * fDigiPar->GetPadSizeY(0); + return dy * fdy + yoff; +} - // get anode wire offset - Int_t ia(0); - Float_t ya; // anode position in local pad coordinates - for (; ia <= NANODE; ia++) { - ya = -1.35 + ia * 0.3; - if (dy > ya + 0.15) continue; - break; +//_______________________________________________________________________________ +void CbmTrdModuleRecT::RecenterXoffset(Double_t& dx) +{ + /** Shift graph representation to fit dx[pw] in [-0.5, 0.5] + */ + + if (dx >= -0.5 && dx < 0.5) return; + Int_t ishift = Int_t(dx - 0.5) + (dx > 0.5 ? 1 : 0); + if (vcM + ishift < 0) ishift = -vcM; + else if (vcM + ishift >= GetNcols()) + ishift = GetNcols() - vcM - 1; + LOG(debug) << GetName() << "::RecenterXoffset : shift dx offset by " << ishift << " from dx=" << dx << " to " + << dx - ishift << " center col from " << (Int_t) vcM << " to " << Int_t(vcM + ishift); + dx -= ishift; + vcM += ishift; + for (UInt_t idx(0); idx < vx.size(); idx++) + vx[idx] -= ishift; +} + + +//_______________________________________________________________________________ +void CbmTrdModuleRecT::RecenterYoffset(Double_t& dy) +{ + /** Shift graph representation to fit dy[ph] in [-0.5, 0.5] + */ + + if (dy >= -0.5 && dy < 0.5) return; + Int_t ishift = Int_t(dy - 0.5) + (dy > 0.5 ? 1 : 0); + // if(vrM+ishift < 0) ishift = - vrM; + // else if(vrM+ishift >= GetNrows()) ishift = GetNrows() - vrM -1; + LOG(debug) << GetName() << "::RecenterYoffset : shift dy offset by " << ishift << " from dy=" << dy << " to " + << dy - ishift; + dy -= ishift; + //vrM+= ishift; + // if(vrM==0 && dy<-0.5) dy=-0.5; + // if(vrM==GetNrows() -1 && dy>0.5) dy=0.5; +} + +//_______________________________________________________________________________ +Int_t CbmTrdModuleRecT::LoadDigis(vector<const CbmTrdDigi*>* din, Int_t cid) +{ + /** Load RAW digis info in calibration aware strucuture CbmTrdDigiReco + * Do basic sanity checks; also incomplete adjacent digi and if found merge them. + */ + Int_t col(-1), /*row, */ colT(-1), colR(-1); + const CbmTrdDigi *dgT(NULL), *dgR(NULL); + for (vector<const CbmTrdDigi*>::iterator i = din->begin(), j = i + 1; i != din->end(); i++) { + dgT = (*i); + //row = + GetPadRowCol(dgT->GetAddressChannel(), colT); + // check column order for cluster + if (col >= 0 && colT != col + 1) { + LOG(error) << GetName() << "::LoadDigis : digis in cluster " << cid << " not in increasing order !"; + return 0; + } + col = colT; + colR = -1; + dgR = NULL; + if (j != din->end()) { + dgR = (*j); + //row = + GetPadRowCol(dgR->GetAddressChannel(), colR); + } + if (colR == colT) { + fDigis[cid].push_back(new CbmTrdDigiRec(*dgT, *dgR)); + j = din->erase(j); + } + else + fDigis[cid].push_back(new CbmTrdDigiRec(*dgT)); + + if (j != din->end()) j++; } + return fDigis[cid].size(); +} - // Error parametrization X : parabolic model on cl size - Double_t parX[] = {0.713724, -0.318667, 0.0366036}; - Int_t nex = TMath::Min(n0, 7); - edx = parX[0] + parX[1] * nex + parX[2] * nex * nex; - Double_t parY[] = {0.0886413, 0., 0.0435141}; - edy = parY[0] + parY[2] * dy * dy; +//_______________________________________________________________________________ +Int_t CbmTrdModuleRecT::ProjectDigis(Int_t cid, Int_t cjd) +{ + /** Load digis information in working vectors Digis are represented in the normal coordinate system of + * (pad width [pw], DAQ time [clk], signal [ADC chs]) with rectangular signals at integer + * positions. + */ + + if (fDigis.find(cid) == fDigis.end()) { + LOG(warn) << GetName() << "::ProjectDigis : Request cl id " << cid << " not found."; + return 0; + } - if (CWRITE()) { - printf("row[%2d] col[%2d] sz[%d%c] M[%d%c] dx[mm]=%6.3f dy[mm]=%6.3f " - "t0[clk]=%llu OVF[%c]\n", - row, col, n0, (lr ? (lr < 0 ? 'L' : 'R') : 'C'), cM, (tM ? 'T' : 'R'), 10 * dx, 10 * dy, t0, - (ovf ? 'y' : 'n')); - for (UInt_t idx(0); idx < vs.size(); idx++) { - printf("%2d%cdt[%2d] s[ADC]=%6.1f+-%6.1f x[pw]=%5.2f+-%5.2f\n", idx, (UInt_t(nL) == idx ? '*' : ' '), vt[idx], - vs[idx], vse[idx], vx[idx], vxe[idx]); + vs.clear(); + vse.clear(); + vx.clear(); + vxe.clear(); + vt.clear(); + vt0 = 0; + vrM = 0; + vcM = 0; + vyM = 0; + viM = 0; + + Bool_t on(0); // flag signal transmition + Int_t n0(0), nsr(0), // no of signals in the cluster (all/rect) + NR(0), nr(0), // no of rect signals/channel in case of RC + NT(0), nt(0), // no of tilt signals/channel in case of RC + ovf(1); // over-flow flag for at least one of the digis + //dt; + Char_t ddt, // signal time offset wrt prompt + dt0(0); // cluster time offset wrt arbitrary t0 + Double_t r, re(100.), // rect signal + t, te(100.), // tilt signal + err, // final error parametrization for signal + xc(-0.5), // running signal-pad position + max(0.); // max signal + Int_t j(0), col(-1), col0(0), col1(0), step(0), row1; + + // link second row if needed + vector<CbmTrdDigiRec*>::iterator i1; + if (cjd >= 0) { + if (fDigis.find(cjd) == fDigis.end()) { + LOG(warn) << GetName() << "::ProjectDigis : Request cl id " << cjd << " not found. Skip second row."; + cjd = -1; } + else + i1 = fDigis[cjd].begin(); } - // compute energy - for (UInt_t idx(0); idx < vs.size(); idx++) { - if (vxe[idx] > 0) { - fgEdep->SetPoint(idx, vx[idx] + dy / fDigiPar->GetPadSizeY(0), vs[idx]); - fgEdep->SetPointError(idx, vxe[idx], vse[idx]); + const CbmTrdDigiRec *dg(NULL), *dg0(NULL), *dg1(NULL); + for (vector<CbmTrdDigiRec*>::iterator i = fDigis[cid].begin(); i != fDigis[cid].end(); i++, j++) { + dg = (*i); + dg0 = NULL; + dg1 = NULL; + if (CWRITE()) cout << "dg0 :" << dg->ToString(); + + // initialize + if (col < 0) { + vrM = GetPadRowCol(dg->GetAddressChannel(), col); + vt0 = dg->GetTimeDAQ(); // set arbitrary t0 to avoid double digis loop } - else { - fgEdep->SetPoint(idx, vx[idx], vs[idx]); - fgEdep->SetPointError(idx, vxe[idx], vse[idx]); + GetPadRowCol(dg->GetAddressChannel(), col0); + nr = nt = 0; + + // read calibrated signals + t = dg->GetTiltCharge(on); + if (on) nt = 1; + r = dg->GetRectCharge(on); + if (on) nr = 1; + // look for matching neighbor digis in case of pad row cross + if (cjd >= 0) { + if ((dg0 = (i1 != fDigis[cjd].end()) ? (*i1) : NULL)) { + row1 = GetPadRowCol(dg0->GetAddressChannel(), col1); + if (!step) step = vrM - row1; + if (col1 == col0) { + r += dg0->GetRectCharge(on); + if (on) nr++; + } + else + dg0 = NULL; + } + if (step == 1 && i1 != fDigis[cjd].begin()) { + dg1 = (*(i1 - 1)); + GetPadRowCol(dg1->GetAddressChannel(), col1); + if (col1 == col0 - 1) { + t += dg1->GetTiltCharge(on); + if (on) nt++; + } + else + dg1 = NULL; + } + if (step == -1 && i1 != fDigis[cjd].end() && i1 + 1 != fDigis[cjd].end()) { + dg1 = (*(i1 + 1)); + GetPadRowCol(dg1->GetAddressChannel(), col1); + if (col1 == col0 + 1) { + t += dg1->GetTiltCharge(on); + if (on) nt++; + } + else + dg1 = NULL; + } + if (dg0) i1++; + } + if (CWRITE()) { + if (dg0) cout << "dgR :" << dg0->ToString(); + if (dg1) cout << "dgT :" << dg1->ToString(); + cout << "-------------------------------------" << endl; } - } - Double_t xc = vx[n0 + 2]; - for (Int_t ip(vs.size()); ip < fgEdep->GetN(); ip++) { - //fgEdep->RemovePoint(ip); - xc += 0.5; - fgEdep->SetPoint(ip, xc, 0); - fgEdep->SetPointError(ip, 0., 300); - } - if (CWRITE()) fgEdep->Print(); - - Double_t e(0.), chi(100), xlo(*vx.begin()), xhi(*vx.rbegin()); - fgPRF->SetParameter(0, max); - fgPRF->FixParameter(1, dx / fDigiPar->GetPadSizeX(0)); - fgPRF->SetParameter(2, 0.65); - fgPRF->SetParLimits(2, 0.45, 10.5); - fgEdep->Fit(fgPRF, "QBN", "goff", xlo - 0.5, xhi + 0.5); - if (!fgPRF->GetNDF()) return NULL; - chi = fgPRF->GetChisquare() / fgPRF->GetNDF(); - e = fgPRF->Integral(xlo - 0.5, xhi + 0.5); - - // apply MC correction - Float_t gain0 = 210.21387; //(XeCO2 @ 1900V) - // Float_t grel[3] = {1., 0.98547803, 0.93164071}, - // goff[3][3] = { - // {0.05714, -0.09, -0.09}, - // {0., -0.14742, -0.14742}, - // {0., -0.29, -0.393} - // }; - // Int_t ian=0; - // if(TMath::Abs(dy)<=0.3) ian=0; - // else if(TMath::Abs(dy)<=0.6) ian=1; - // else if(TMath::Abs(dy)<=0.9) ian=2; - // Int_t isize=0; - // if(n0<=3) isize=0; - // else if(n0<=4) isize=1; - // else isize=2; - Float_t gain = gain0; //*grel[ian]; - e /= gain; // apply effective gain - //e+=goff[ian][isize]; // apply missing energy offset - TVector3 local_pad, local_pad_err; - Int_t srow, sector = fDigiPar->GetSectorRow(row, srow); - fDigiPar->GetPadPosition(sector, col, srow, local_pad, local_pad_err); - //printf("r[%2d] c[%2d] max[%d] lr[%d] n0[%d] cM[%d] nM[%d] dx[%7.4f] dy[%7.4f] loc[%6.2f %6.2f %6.2f] err[%6.2f %6.2f %6.2f] e[%f] chi[%f]\n", row, col, mtyp, lr, n0, cM, nM, dx, dy, local_pad[0], local_pad[1], local_pad[2], local_pad_err[0], local_pad_err[1], local_pad_err[2], e, chi); - Double_t local[3] = {local_pad[0] + dx, local_pad[1] + dy, local_pad[2]}, global[3], globalErr[3] = {edx, edy, 0.}; - LocalToMaster(local, global); + // process tilt signal/time + ddt = dg->GetTiltTime() - vt0; + if (ddt < dt0) dt0 = ddt; + if (abs(t) > 0) { + if (nt > 1) t *= 0.5; + err = te * (nt > 1 ? 0.707 : 1); + if (dg->HasTiltOvf()) { + ovf = -1; + err = 150.; + } + if (t > max) { + max = t; + vcM = j; + SetMaxTilt(1); + viM = vs.size(); + } + } + else + err = 300.; + vt.push_back(ddt); + vs.push_back(t); + vse.push_back(err); + vx.push_back(xc); + vxe.push_back(0.035); + xc += 0.5; - // process time profile - for (Int_t idx(1); idx <= n0; idx++) { - Double_t dtFEE = - fgDT[0] * (vs[idx] - fgDT[1]) * (vs[idx] - fgDT[1]) / CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kFASP); - if (vxe[idx] > 0) vx[idx] += dy / fDigiPar->GetPadSizeY(0); - fgT->SetPoint(idx - 1, vx[idx], vt[idx] - dtFEE); - } - xc = vx[n0 + 2]; - for (Int_t ip(n0); ip < fgT->GetN(); ip++) { - fgT->SetPoint(ip, xc, 0); + // process rect signal/time + ddt = dg->GetRectTime() - vt0; + if (ddt < dt0) dt0 = ddt; + if (abs(r) > 0) { + nsr++; + if (nr > 1) r *= 0.5; + err = re * (nr > 1 ? 0.707 : 1); + if (dg->HasRectOvf()) { + ovf = -1; + err = 150.; + } + if (r > max) { + max = r; + vcM = j; + SetMaxTilt(0); + viM = vs.size(); + } + } + else + err = 300.; + vt.push_back(ddt); + vs.push_back(r); + vse.push_back(err); + vx.push_back(xc); + vxe.push_back(0.); xc += 0.5; + NR += nr; + NT += nt; } - Double_t time(-21.), - edt(26.33), // should be parametrized as function of da TODO - tdrift(100); // should depend on Ua - if (n0 > 1 && (fgT->Fit("pol1", "QC", "goff") == 0)) { - TF1* f = fgT->GetFunction("pol1"); - time = f->GetParameter(0) - fgDT[2]; - if (TMath::IsNaN(time)) time = -21; - //dtime += TMath::Abs(f->GetParameter(1)*(vx[n0+1] - vx[1])); + // add front and back anchor points if needed + if (TMath::Abs(vs[0]) > 1.e-3) { + xc = vx[0]; + ddt = vt[0]; + vs.insert(vs.begin(), 0); + vse.insert(vse.begin(), 300); + vt.insert(vt.begin(), ddt); + vx.insert(vx.begin(), xc - 0.5); + vxe.insert(vxe.begin(), 0); + viM++; } - - if (CDRAW()) { - Double_t rangex(vx[0] - 0.25), rangeX(vx[n0 + 2] + 0.25); - cvs->cd(1); - hf->Draw("p"); - hf->GetXaxis()->SetRangeUser(rangex, rangeX); - hf->SetTitle(Form("%d[%d] row[%d] col[%2d] an[%+d] m[%+4.2f] s[%4.2f] E[%7.2f] chi2[%7.2f]", ic, Int_t(vs.size()), - row, col, ia, fgPRF->GetParameter(1), fgPRF->GetParameter(2), e, chi)); - hf->GetXaxis()->SetRangeUser(rangex, rangeX); - hf->GetYaxis()->SetRangeUser(-100., 4500); - fgEdep->Draw("pl"); - fgPRF->Draw("same"); - - cvs->cd(2); - hf = (TH1*) hf->DrawClone("p"); - hf->GetXaxis()->SetRangeUser(rangex, rangeX); - hf->GetYaxis()->SetRangeUser(-10, 20); - //hf->SetTitle(Form("%d row[%d] col[%2d] an[%+d] m[%+4.2f] s[%4.2f] E[%7.2f] chi2[%7.2f]", ic, row, col, ia, fgPRF->GetParameter(1), fgPRF->GetParameter(2), fgPRF->Integral(xlo, xhi), fgPRF->GetChisquare()/fgPRF->GetNDF())); - // hf->GetXaxis()->SetRangeUser(xlo-0.25, xhi+0.25); - // //hf->GetYaxis()->SetRangeUser(0., 4500); - fgT->Draw("pl"); - cvs->Modified(); - cvs->Update(); - cvs->SaveAs(Form("cl_%02d_A%d.gif", ic, ia)); + Int_t n(vs.size() - 1); + if (TMath::Abs(vs[n]) > 1.e-3) { + xc = vx[n] + 0.5; + ddt = vt[n]; + vs.push_back(0); + vse.push_back(300); + vt.push_back(ddt); + vx.push_back(xc); + vxe.push_back(0.035); } - Int_t nofHits = fHits->GetEntriesFast(); - CbmTrdHit* hit = new ((*fHits)[nofHits]) - CbmTrdHit(fModAddress, global, globalErr, - 0., // sxy chi, - ic, - e, // energy - CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kFASP) * (t0 + time) - tdrift + 30.29, edt); - hit->SetClassType(); - hit->SetMaxType(tM); - if (ovf) hit->SetOverFlow(); - if (CWRITE()) cout << hit->ToString(); - return hit; -} - -//_______________________________________________________________________________ -Double_t CbmTrdModuleRecT::GetXoffset(Int_t n0) const -{ - Double_t dx(0.), R(0.); - for (Int_t ir(1); ir <= n0; ir++) { - if (vxe[ir] > 0) continue; // select rectangular coupling - R += vs[ir]; - dx += vs[ir] * vx[ir]; + n0 = vs.size() - 2; + // compute cluster asymmetry + Int_t nR = n0 + 1 - viM; + if (nR == viM) { + SetSymmHit(1); + if (vs.size() % 2) { + Double_t LS(0.), RS(0.); + for (UChar_t idx(0); idx < viM; idx++) + LS += vs[idx]; + for (UInt_t idx(viM + 1); idx < vx.size(); idx++) + RS += vs[idx]; + SetLeftSgn(LS < RS ? 0 : 1); + } } - if (TMath::Abs(R) > 0) return dx / R; - LOG(warn) << GetName() << "::GetDx : Unexpected null sum."; - return 0.; -} + else { + SetSymmHit(0); + if (viM < nR) SetLeftHit(0); + else if (viM > nR) + SetLeftHit(1); + } + // recenter time and space profile + vt0 += dt0; + for (UInt_t idx(0); idx < vx.size(); idx++) { + vt[idx] -= dt0; + vx[idx] -= vcM; + } + vcM += col; + + // check if all signals have same significance + Int_t nmiss = 2 * nsr - NR; //printf("R : nsr[%d] NR[%d] nmiss[%d]\n", nsr, NR, nmiss); + if (cjd >= 0 && nmiss) { + SetBiasX(1); + for (UChar_t idx(1); idx < viM; idx++) { + if (vxe[idx] > 0.) continue; // select rect signals + if (vse[idx] > re * 0.8) SetBiasXleft(1); + } + if (vxe[viM] <= 0. && vse[viM] > re * 0.8) SetBiasXmid(1); + for (UChar_t idx(viM + 1); idx < vs.size() - 1; idx++) { + if (vxe[idx] > 0.) continue; // select rect signals + if (vse[idx] > re * 0.8) SetBiasXright(1); + } + } + else + SetBiasX(0); + nmiss = 2 * n0 - 2 * nsr - NT; //printf("T : n0[%d] nsr[%d] NT[%d] nmiss[%d]\n", n0, nsr, NT, nmiss); + if (cjd >= 0 && nmiss) { + SetBiasY(); + for (UChar_t idx(1); idx < viM; idx++) { + if (vxe[idx] > 0. && vse[idx] > te * 0.8) SetBiasYleft(1); // select tilt signals + } + if (vxe[viM] > 0. && vse[viM] > te * 0.8) SetBiasYmid(1); + for (UChar_t idx(viM + 1); idx < vs.size() - 1; idx++) { + if (vxe[idx] > 0. && vse[idx] > te * 0.8) SetBiasYright(1); // select tilt signals + } + } + else + SetBiasY(0); -//_______________________________________________________________________________ -Double_t CbmTrdModuleRecT::GetYoffset(Int_t n0) const -{ - Double_t dy(0.), T(0.); - for (Int_t it(1); it <= n0; it++) { - if (vxe[it] > 0) { // select tilted coupling - T += vs[it]; - dy += vs[it] * vx[it]; + if (CWRITE()) { + printf("t0[clk]=%llu col[%2d] row[%2d] sz[%d] OVF[%c] %c", vt0, vcM, vrM, Int_t(vs.size() - 2), + (ovf < 0 ? 'y' : 'n'), IsOpenLeft() ? '(' : '['); + if (IsSymmHit()) { + if (HasLeftSgn()) printf("<|"); + else + printf("|>"); + } + else + printf("%s", IsLeftHit() ? "<<" : ">>"); + printf("%c bias[%c %c]\n", IsOpenRight() ? ')' : ']', IsBiasX() ? (IsBiasXleft() ? '<' : '>') : 'o', + IsBiasY() ? (IsBiasYleft() ? '<' : '>') : 'o'); + for (UInt_t idx(0); idx < vs.size(); idx++) { + printf("%2d dt[%2d] s[ADC]=%6.1f+-%6.1f x[pw]=%5.2f+-%5.2f ", idx, vt[idx], vs[idx], vse[idx], vx[idx], vxe[idx]); + if (idx == viM) printf("[%s]", (IsMaxTilt() ? "//" : "||")); + printf("\n"); } } - if (TMath::Abs(T) > 0) return dy / T; - LOG(warn) << GetName() << "::GetDy : Unexpected null sum."; - return 0.; + + if (ovf < 0) SetOvf(); //printf("SetOvf %d\n", vyM); } + return ovf * (vs.size() - 2); } //_______________________________________________________________________________ Int_t CbmTrdModuleRecT::LoadDigis(vector<const CbmTrdDigi*>* digis, vector<CbmTrdDigi*>* vdgM, vector<Bool_t>* vmask, ULong64_t& t0, Int_t& cM) { - /* Load digis information in working vectors. + /** Load digis information in working vectors. * The digis as provided by the digitizer are replaced by the merged one * according to the vmask map. Digis are represented in the normal coordinate system of * (pad width [pw], DAQ time [clk], signal [ADC chs]) with rectangular signals at integer @@ -772,6 +1446,206 @@ Int_t CbmTrdModuleRecT::LoadDigis(vector<const CbmTrdDigi*>* digis, vector<CbmTr return ovf * n0; } + +//_______________________________________________________________________________ +Int_t CbmTrdModuleRecT::LoadDigisRC(vector<const CbmTrdDigi*>* digis, const Int_t r0, const Int_t a0, + /*vector<CbmTrdDigi*> *vdgM, */ ULong64_t& t0, Int_t& cM) +{ + /** Load digis information for row-cross hits in working vectors. + * The digis as provided by the digitizer are replaced by the merged one (TODO) + * according to the vmask map. Digis are represented in the normal coordinate system of + * (pad width [pw], DAQ time [clk], signal [ADC chs]) with rectangular signals at integer + * positions. + * TODO + * 1. Time information in the secondary row not used. + * 2. Time walk (dependence on charge) not recovered by calibration. + * + */ + vs.clear(); + vse.clear(); + vx.clear(); + vxe.clear(); + vt.clear(); + + cM = 0; // relative position of maximum signal + Int_t step, + n0(0), // number of measured signals + ovf(1), // over-flow flag for at least one of the digis + dt, dT; + Char_t ddt, // signal time offset wrt prompt + dt0(0); // cluster time offset wrt arbitrary t0 + Double_t r, R, re(100.), // rect signal + t, T, te(100.), // tilt signal + err, // final error parametrization for signal + xc(0.), // running signal-pad position + max(0.); // max signal + Int_t j(0), row, col, col0(-1), col1(0); + //vector<CbmTrdDigi*>::iterator idgM=vdgM->begin(); + + vector<const CbmTrdDigi*>::iterator i0, i1, ix0, ix1; + i0 = digis->begin(); + i1 = i0; + do { + row = GetPadRowCol((*i1)->GetAddressChannel(), col1); + if (col0 < 0) col0 = col1; + if (row == r0) i1++; + else + break; + } while (i1 != digis->end()); + ix0 = i1; + ix1 = digis->end(); + col = col0; + step = -1; + if (a0 > 0) { + i0 = i1; + ix0 = digis->end(); + ix1 = i1; + i1 = digis->begin(); + col = col0; + col0 = col1; + col1 = col; + col = col0; + step = 1; + } + if (CWRITE()) printf("col0[%d] col1[%d] step[%2d]\n", col0, col1, step); + const CbmTrdDigi *dg0(NULL), *dg1(NULL), *dg10(NULL); + + // always loop on the largest cluster + for (; i0 != ix0; i0++, j++) { + dg0 = (*i0); + dg1 = NULL; + dg10 = NULL; + if (CWRITE()) cout << "dg0 :" << dg0->ToString(); + + r = dg0->GetCharge(t, dt); + if (t > 0) t -= CbmTrdFASP::GetBaselineCorr(); + if (r > 0) r -= CbmTrdFASP::GetBaselineCorr(); + + if (t0 == 0) t0 = dg0->GetTimeDAQ(); // set arbitrary t0 to avoid double digis loop + ddt = dg0->GetTimeDAQ() - t0; + if (ddt < dt0) dt0 = ddt; + + // check column wise organization + row = GetPadRowCol(dg0->GetAddressChannel(), col0); + if (col + j != col0) { + LOG(error) << GetName() << "::LoadDigisRC : digis in cluster not in increasing order " << col0 << " !"; + return 0; + } + + // look for matching neighbor digis + if ((dg1 = (i1 != ix1) ? (*i1) : NULL)) { + GetPadRowCol(dg1->GetAddressChannel(), col1); + if (col1 == col0) { + R = dg1->GetCharge(T, dT); + if (R > 0.) r += R - CbmTrdFASP::GetBaselineCorr(); + } + else + dg1 = NULL; + } + if (step == 1 && i1 != digis->begin()) { + dg10 = (*(i1 - 1)); + GetPadRowCol(dg10->GetAddressChannel(), col1); + if (col1 == col0 - 1) { + dg10->GetCharge(T, dT); + if (T > 0.) t += T - CbmTrdFASP::GetBaselineCorr(); + } + else + dg10 = NULL; + } + if (step == -1 && i1 != ix1 && i1 + 1 != ix1) { + dg10 = (*(i1 + 1)); + GetPadRowCol(dg10->GetAddressChannel(), col1); + if (col1 == col0 + 1) { + dg10->GetCharge(T, dT); + if (T > 0.) t += T - CbmTrdFASP::GetBaselineCorr(); + } + else + dg10 = NULL; + } + if (dg1) i1++; + + if (CWRITE()) { + if (dg1) cout << "dgR :" << dg1->ToString(); + if (dg10) cout << "dgT :" << dg10->ToString(); + cout << "-------------------------------------" << endl; + } + + // process tilt signal + if (t > 0) { + err = te; + n0++; + if (t > max) { + max = t; + cM = j; + } + } + else + err = 300.; + vt.push_back(ddt); + vs.push_back(t); + vse.push_back(err); + vx.push_back(xc); + vxe.push_back(0.035); + + // process rect signal + ddt += dt; + if (ddt < dt0) dt0 = ddt; + if (r > 0) { + err = re; + n0++; + if (r > max) { + max = r; + cM = j; + } + } + else + err = 300.; + vt.push_back(ddt); + vs.push_back(r); + vse.push_back(err); + vx.push_back(xc); + vxe.push_back(0.); + xc += 1; + } + + // // remove merged digis if they were created + // if(idgM != vdgM->end()) LOG(warn) << GetName() << "::LoadDigis : not all merged digis have been consumed !"; + // for(idgM=vdgM->begin(); idgM!=vdgM->end(); idgM++) delete (*idgM); + // + // add front and back anchor points if needed + if (TMath::Abs(vs[0]) > 1.e-3) { + xc = vx[0]; + ddt = vt[0]; + vs.insert(vs.begin(), 0); + vse.insert(vse.begin(), 300); + vt.insert(vt.begin(), ddt); + vx.insert(vx.begin(), xc - 1); + vxe.insert(vxe.begin(), 0); + } + Int_t n(vs.size() - 1); + if (TMath::Abs(vs[n]) > 1.e-3) { + xc = vx[n] + 1; + ddt = vt[n]; + vs.push_back(0); + vse.push_back(300); + vt.push_back(ddt); + vx.push_back(xc); + vxe.push_back(0.035); + } + + // recenter time and space profile + if (cM + col >= fDigiPar->GetNofColumns()) cM = fDigiPar->GetNofColumns() - col - 1; + else if (cM + col < 0) + cM = -col; + t0 += dt0; + for (UInt_t idx(0); idx < vx.size(); idx++) { + vt[idx] -= dt0; + vx[idx] -= cM; + } + cM += col; + return ovf * n0; +} + //_______________________________________________________________________________ Bool_t CbmTrdModuleRecT::MergeDigis(vector<const CbmTrdDigi*>* digis, vector<CbmTrdDigi*>* vdgM, vector<Bool_t>* vmask) { @@ -828,33 +1702,47 @@ Bool_t CbmTrdModuleRecT::MergeDigis(vector<const CbmTrdDigi*>* digis, vector<Cbm return kTRUE; } -Float_t CbmTrdModuleRecT::fgCorrXdx = 0.005; -Float_t CbmTrdModuleRecT::fgCorrXval[2][NBINSCORRX] = { - {0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, - 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, -0.144, -0.091, -0.134, -0.185, -0.120, -0.115, -0.125, - -0.125, -0.124, -0.124, -0.122, -0.120, -0.119, -0.116, -0.114, -0.113, -0.111, -0.109, -0.107, -0.105, -0.102, - -0.100, -0.098, -0.097, -0.093, -0.091, -0.089, -0.087, -0.084, -0.082, -0.079, -0.077, -0.074, -0.072, -0.068, - -0.065, -0.062, -0.059, -0.056, -0.053, -0.049, -0.046, -0.043, -0.039, -0.036, -0.032, -0.029, -0.025, -0.022, - -0.018, -0.015, -0.011, -0.007, -0.003, 0.000, 0.003, 0.007, 0.011, 0.014, 0.018, 0.022, 0.025, 0.029, - 0.032, 0.036, 0.039, 0.043, 0.046, 0.049, 0.053, 0.056, 0.059, 0.062, 0.065, 0.068, 0.071, 0.074, - 0.077, 0.080, 0.082, 0.084, 0.087, 0.090, 0.091, 0.094, 0.096, 0.098, 0.100, 0.103, 0.104, 0.107, - 0.108, 0.110, 0.113, 0.115, 0.116, 0.120, 0.121, 0.121, 0.123, 0.125, 0.124, 0.127, 0.140, 0.119, - 0.114, 0.028, 0.049, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, - 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000}, - {0.003, 0.013, 0.026, 0.039, 0.052, 0.065, 0.078, 0.091, 0.104, 0.118, 0.132, 0.145, 0.160, 0.174, - 0.189, 0.203, 0.219, 0.234, 0.250, 0.267, 0.283, 0.301, 0.319, 0.338, 0.357, 0.375, 0.398, 0.419, - 0.440, 0.464, 0.491, 0.514, 0.541, 0.569, 0.598, 0.623, 0.660, 0.696, 0.728, 0.763, 0.804, 0.847, - 0.888, 0.930, 0.988, 1.015, 1.076, 1.128, 1.167, 1.228, 1.297, 1.374, 1.443, 1.511, 1.564, 0.000, - 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, - 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, - 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, -1.992, -1.884, -1.765, -1.703, -1.609, -1.572, -1.493, - -1.426, -1.356, -1.309, -1.243, -1.202, -1.109, -1.069, -1.026, -0.970, -0.933, -0.881, -0.844, -0.803, -0.767, - -0.721, -0.691, -0.659, -0.629, -0.596, -0.569, -0.541, -0.514, -0.490, -0.466, -0.441, -0.419, -0.397, -0.377, - -0.357, -0.337, -0.319, -0.301, -0.283, -0.267, -0.250, -0.234, -0.218, -0.203, -0.189, -0.174, -0.160, -0.145, - -0.131, -0.119, -0.104, -0.091, -0.078, -0.064, -0.052, -0.039, -0.026, -0.013, -0.002}}; -Float_t CbmTrdModuleRecT::fgCorrYval[NBINSCORRY][2] = {{2.421729, 0.}, - {1.537359, 0.483472}, - {1.1752, 0.}, - {1.154183, -0.090229}}; + +Float_t CbmTrdModuleRecT::fgCorrXdx = 0.01; +Float_t CbmTrdModuleRecT::fgCorrXval[3][NBINSCORRX] = { + {-0.001, -0.001, -0.002, -0.002, -0.003, -0.003, -0.003, -0.004, -0.004, -0.006, -0.006, -0.006, -0.007, + -0.007, -0.008, -0.008, -0.008, -0.009, -0.009, -0.011, -0.011, -0.011, -0.012, -0.012, -0.012, -0.012, + -0.013, -0.013, -0.013, -0.013, -0.014, -0.014, -0.014, -0.014, -0.014, -0.016, -0.016, -0.016, -0.016, + -0.017, -0.017, -0.017, -0.018, -0.018, -0.018, -0.018, -0.018, 0.000, 0.000, 0.000}, + {0.467, 0.430, 0.396, 0.364, 0.335, 0.312, 0.291, 0.256, 0.234, 0.219, 0.207, 0.191, 0.172, + 0.154, 0.147, 0.134, 0.123, 0.119, 0.109, 0.122, 0.113, 0.104, 0.093, 0.087, 0.079, 0.073, + 0.067, 0.063, 0.058, 0.053, 0.049, 0.046, 0.042, 0.038, 0.036, 0.032, 0.029, 0.027, 0.024, + 0.022, 0.019, 0.017, 0.014, 0.013, 0.011, 0.009, 0.007, 0.004, 0.003, 0.001}, + {0.001, 0.001, 0.001, 0.001, 0.002, 0.002, 0.001, 0.002, 0.004, 0.003, 0.002, 0.002, 0.002, + 0.002, 0.002, 0.002, 0.003, 0.004, 0.003, 0.004, 0.004, 0.007, 0.003, 0.004, 0.002, 0.002, + -0.011, -0.011, -0.012, -0.012, -0.012, -0.013, -0.013, -0.013, -0.014, -0.014, -0.014, -0.016, -0.016, + -0.016, -0.017, -0.017, -0.017, -0.018, -0.018, -0.018, -0.019, 0.029, 0.018, 0.001}}; +Float_t CbmTrdModuleRecT::fgCorrYval[NBINSCORRY][2] = {{2.421729, 0.}, + {0.629389, -0.215285}, + {0.23958, 0.}, + {0.151913, 0.054404}}; +Float_t CbmTrdModuleRecT::fgCorrRcXval[2][NBINSCORRX] = { + {-0.00050, -0.00050, -0.00150, -0.00250, -0.00250, -0.00350, -0.00450, -0.00450, -0.00550, -0.00650, + -0.00650, -0.00750, -0.00850, -0.00850, -0.00850, -0.00950, -0.00950, -0.00950, -0.01050, -0.01150, + -0.01150, -0.01150, -0.01250, -0.01250, -0.01250, -0.01250, -0.01350, -0.01350, -0.01350, -0.01350, + -0.01450, -0.01450, -0.01450, -0.01550, -0.01550, -0.01550, -0.01550, -0.01650, -0.01650, -0.01550, + -0.01650, -0.01614, -0.01620, -0.01624, -0.01626, -0.01627, -0.01626, -0.01624, -0.01620, -0.01615}, + {0.36412, 0.34567, 0.32815, 0.31152, 0.29574, 0.28075, 0.26652, 0.25302, 0.24020, 0.22803, 0.21647, 0.21400, 0.19400, + 0.18520, 0.17582, 0.16600, 0.14600, 0.13800, 0.14280, 0.14200, 0.13400, 0.12600, 0.12200, 0.11000, 0.10200, 0.09400, + 0.09000, 0.08600, 0.08200, 0.07400, 0.07000, 0.06600, 0.06600, 0.06200, 0.05800, 0.05400, 0.05400, 0.05000, 0.04600, + 0.04600, 0.04200, 0.03800, 0.03800, 0.03400, 0.03400, 0.03000, 0.03000, 0.02600, 0.02200, 0.02200}}; +Float_t CbmTrdModuleRecT::fgCorrRcXbiasXval[3][NBINSCORRX] = { + {0.00100, 0.00260, 0.00540, 0.00740, 0.00900, 0.01060, 0.01300, 0.01460, 0.01660, 0.01900, 0.02060, 0.02260, 0.02420, + 0.02700, 0.02860, 0.02980, 0.03220, 0.03340, 0.03540, 0.03620, 0.03820, 0.04020, 0.04180, 0.04340, 0.04460, 0.04620, + 0.04740, 0.04941, 0.05088, 0.05233, 0.05375, 0.05515, 0.05653, 0.05788, 0.05921, 0.06052, 0.06180, 0.06306, 0.06430, + 0.06551, 0.06670, 0.06786, 0.06901, 0.07012, 0.07122, 0.07229, 0.07334, 0.07436, 0.07536, 0.07634}, + {0.00100, 0.00380, 0.00780, 0.00900, 0.01220, 0.01460, 0.01860, 0.01940, 0.02260, 0.02540, 0.02820, 0.03060, 0.03220, + 0.03660, 0.03980, 0.04094, 0.04420, 0.04620, 0.04824, 0.04980, 0.05298, 0.05532, 0.05740, 0.05991, 0.06217, 0.06500, + 0.06540, 0.06900, 0.07096, 0.07310, 0.07380, 0.07729, 0.07935, 0.08139, 0.08340, 0.08538, 0.08734, 0.08928, 0.08900, + 0.09307, 0.09493, 0.09340, 0.09858, 0.09620, 0.09740, 0.10386, 0.09980, 0.10726, 0.10892, 0.11056}, + {0.00011, 0.00140, 0.00340, 0.00420, 0.00500, 0.00620, 0.00820, 0.00860, 0.01060, 0.01100, 0.01220, 0.01340, 0.01500, + 0.01540, 0.01700, 0.01820, 0.01900, 0.02060, 0.02180, 0.02260, 0.02340, 0.02420, 0.02500, 0.02500, 0.02660, 0.02740, + 0.02820, 0.02900, 0.03020, 0.03180, 0.03300, 0.03260, 0.03380, 0.03460, 0.03500, 0.03580, 0.03780, 0.03820, 0.03860, + 0.03900, 0.04100, 0.04180, 0.04060, 0.04300, 0.04340, 0.04340, 0.04380, 0.04460, 0.04580, 0.04540}}; ClassImp(CbmTrdModuleRecT) diff --git a/reco/detectors/trd/CbmTrdModuleRecT.h b/reco/detectors/trd/CbmTrdModuleRecT.h index 39d577e13d3cf9efada27284066d0c37678f4751..6c6e96d3c098d3c56d49b9ca371fada58716c48e 100644 --- a/reco/detectors/trd/CbmTrdModuleRecT.h +++ b/reco/detectors/trd/CbmTrdModuleRecT.h @@ -10,14 +10,29 @@ #include <list> #include <map> #include <vector> -#define NBINSCORRX 151 //! no of bins in the discretized correction LUT +#define NBINSCORRX 50 //! no of bins in the discretized correction LUT #define NBINSCORRY 4 //! no of bins in the parametrization correction +#define NANODE 9 +using std::list; +using std::map; +using std::vector; class TGraphErrors; +class CbmTrdDigiRec; class TF1; -/** - * \brief Triangular pad module; Cluster finding and hit reconstruction algorithms - **/ +/** @class CbmTrdModuleRecT + ** @brief Cluster finding and hit reconstruction algorithms for the TRD(2D) module. + ** @author Alexandru Bercucic <abercuci@niham.nipne.ro> + ** @since 01.02.2019 + ** @date 01.10.2021 + ** + ** Extend the TRD module reconstructor for the particular case of inner TRD-2D modules. + ** The class is a collection of algorithms to : + ** - identify time and spatially correlated digis and build clusters + ** - identify the type of clusters and apply further merging/deconvolution + ** - apply FEE (channel gain, baseline) and detector (energy gain, maps, etc) calibration + ** - steer the calculation of hit 4D parameters (x, y, t, E) + **/ class CbmTrdModuleRecT : public CbmTrdModuleRec { public: enum CbmTrdModuleRecTconfig @@ -41,16 +56,67 @@ public: * \param[in] d drawing toggle */ virtual inline void Config(Bool_t v, Bool_t d); + virtual void DrawHit(CbmTrdHit*) const { ; } /** \brief Count RO channels (R or T) with data**/ virtual Int_t GetOverThreshold() const; + /** \brief Check hit quality (deconvolute pile-ups, etc)**/ + virtual Bool_t PreProcessHits(); /** \brief Finalize hits (merge RC hits, etc)**/ - virtual Bool_t Finalize(); + virtual Bool_t PostProcessHits(); /** \brief Finalize clusters **/ virtual Int_t FindClusters(); /** \brief Steering routine for building hits **/ virtual Bool_t MakeHits(); /** \brief Steering routine for converting cluster to hit **/ virtual CbmTrdHit* MakeHit(Int_t cId, const CbmTrdCluster* c, std::vector<const CbmTrdDigi*>* digis); + /** \brief Load RAW digis into working array of RECO digis + * \param[in] din list of RAW digis in increasing order of column no + * \param[in] cid cluster index in the cluster array + * \return no of digis loaded + */ + Int_t LoadDigis(vector<const CbmTrdDigi*>* din, Int_t cid); + Int_t ProjectDigis(Int_t cid, Int_t cjd = -1); + /** \brief Implement topologic cuts for hit merging + * \return index of anode wire wrt to boundary or 0 if check fails + */ + Int_t CheckMerge(Int_t cid, Int_t cjd); + /** \brief Algorithm for hit merging + * \param[in] h hit to be modified by addition of hp. + * \param[in] a0 anode hypothesis around boundary (see CheckMerge function). + * \return TRUE if succesful. + */ + Bool_t MergeHits(CbmTrdHit* h, Int_t a0); + Bool_t BuildHit(CbmTrdHit* h); + UShort_t GetHitMap() const { return vyM; } + /** \brief x position correction based on LUT + * \param[in] dx offset computed on charge sharing expressed in [pw] + * \param[in] typ hit type central pad [0] or edge [1] + * \param[in] cls correction class x wrt center [0] row-cross [1] row-cross biassed x [2] + * \return correction expresed in [cm] + */ + Double_t GetXcorr(Double_t dx, Int_t typ, Int_t cls = 0) const; + /** \brief y position correction based on LUT + * \param[in] dy offset computed on charge sharing expressed in [ph] + * \param[in] cls correction class + * \return correction expresed in [cm] + */ + Double_t GetYcorr(Double_t dy, Int_t cls = 0) const; + /** \brief Shift graph representation to [-0.5, 0.5] + * \param[in] dx offset wrt center pad [pw] + */ + void RecenterXoffset(Double_t& dx); + /** \brief Shift graph representation to [-0.5, 0.5] + * \param[in] dy offset wrt center pad [ph] + */ + void RecenterYoffset(Double_t& dy); + /** \brief Hit classification wrt center pad + * \return hit type : center hit [0]; side hit [1] + */ + Int_t GetHitClass() const; + /** \brief Hit classification wrt signal bias + * \return hit type : center hit [0]; side hit [1] + */ + Int_t GetHitRcClass(Int_t a0) const; protected: private: @@ -59,8 +125,18 @@ private: Bool_t CDRAW() const { return TESTBIT(fConfigMap, kDraw); } Bool_t CWRITE() const { return TESTBIT(fConfigMap, kVerbose); } - Double_t GetXoffset(Int_t n0) const; - Double_t GetYoffset(Int_t n0) const; + /** \brief Implement cuts for hit convolution definition + * \param[in] h hit to be analysed. + * \return TRUE if double cluster + */ + Bool_t CheckConvolution(CbmTrdHit* h) const; + /** \brief Algorithm for cluster spliting + * \param[in] h hit to be analysed. + * \return TRUE if succesful. The extra cluster is added to the end of the hits array + */ + Bool_t Deconvolute(CbmTrdHit* h); + Double_t GetXoffset(Int_t n0 = 0) const; + Double_t GetYoffset(Int_t n0 = 0) const; /** \brief Load digis info into local data structures * \param[in] digis initial digis list shrinked for incomplete digis. * \param[in] vdgM list of merged digis @@ -71,6 +147,9 @@ private: */ Int_t LoadDigis(std::vector<const CbmTrdDigi*>* digis, std::vector<CbmTrdDigi*>* vdgM, std::vector<Bool_t>* vmask, ULong64_t& t0, Int_t& cM); + Int_t LoadDigisRC(vector<const CbmTrdDigi*>* digis, const Int_t r0, const Int_t a0, + /*vector<CbmTrdDigi*> *vdgM, */ ULong64_t& t0, Int_t& cM); + /** \brief Merge R/T signals to digis if topological conditions in cluster are fulfilled * \param[in] digis initial digis list. * \param[out] vdgM list of merged digis @@ -79,25 +158,61 @@ private: */ Bool_t MergeDigis(std::vector<const CbmTrdDigi*>* digis, std::vector<CbmTrdDigi*>* vdgM, std::vector<Bool_t>* vmask); + Bool_t HasLeftSgn() const { return TESTBIT(vyM, 3); } + Bool_t HasOvf() const { return TESTBIT(vyM, 12); } + Bool_t IsBiasX() const { return TESTBIT(vyM, 4); } + Bool_t IsBiasXleft() const { return TESTBIT(vyM, 5); } + Bool_t IsBiasXmid() const { return TESTBIT(vyM, 6); } + Bool_t IsBiasXright() const { return TESTBIT(vyM, 7); } + Bool_t IsBiasY() const { return TESTBIT(vyM, 8); } + Bool_t IsBiasYleft() const { return TESTBIT(vyM, 9); } + Bool_t IsLeftHit() const { return TESTBIT(vyM, 2); } + Bool_t IsMaxTilt() const { return TESTBIT(vyM, 0); } + Bool_t IsOpenLeft() const { return (viM % 2 && !IsMaxTilt()) || (!(viM % 2) && IsMaxTilt()); } + inline Bool_t IsOpenRight() const; + Bool_t IsSymmHit() const { return TESTBIT(vyM, 1); } + void SetBiasX(Bool_t set = 1) { set ? SETBIT(vyM, 4) : CLRBIT(vyM, 4); } + void SetBiasXleft(Bool_t set = 1) { set ? SETBIT(vyM, 5) : CLRBIT(vyM, 5); } + void SetBiasXmid(Bool_t set = 1) { set ? SETBIT(vyM, 6) : CLRBIT(vyM, 6); } + void SetBiasXright(Bool_t set = 1) { set ? SETBIT(vyM, 7) : CLRBIT(vyM, 7); } + void SetBiasY(Bool_t set = 1) { set ? SETBIT(vyM, 8) : CLRBIT(vyM, 8); } + void SetBiasYleft(Bool_t set = 1) { set ? SETBIT(vyM, 9) : CLRBIT(vyM, 9); } + void SetBiasYmid(Bool_t set = 1) { set ? SETBIT(vyM, 10) : CLRBIT(vyM, 10); } + void SetBiasYright(Bool_t set = 1) { set ? SETBIT(vyM, 11) : CLRBIT(vyM, 11); } + void SetLeftSgn(Bool_t set = 1) { set ? SETBIT(vyM, 3) : CLRBIT(vyM, 3); } + void SetLeftHit(Bool_t set = 1) { set ? SETBIT(vyM, 2) : CLRBIT(vyM, 2); } + void SetSymmHit(Bool_t set = 1) { set ? SETBIT(vyM, 1) : CLRBIT(vyM, 1); } + void SetMaxTilt(Bool_t set = 1) { set ? SETBIT(vyM, 0) : CLRBIT(vyM, 0); } + void SetOvf(Bool_t set = 1) { set ? SETBIT(vyM, 12) : CLRBIT(vyM, 12); } + UChar_t fConfigMap; // task configuration settings ULong64_t fT0; //! start time of event/time slice [clk] std::map<Int_t, std::list<CbmTrdCluster*>> fBuffer; //row-wise organized clusters - std::vector<Double_t> vs; //! working copy of signals from cluster - std::vector<Double_t> vse; //! working copy of signal errors from cluster - std::vector<Char_t> vt; //! working copy of signal relative timing - std::vector<Double_t> vx; //! working copy of signal relative positions - std::vector<Double_t> vxe; //! working copy of signal relative position errors + std::map<Int_t, vector<CbmTrdDigiRec*>> fDigis; //!cluster-wise organized calibrated digi + // working representation of a hit on which the reconstruction is performed + ULong64_t vt0; //! start time of current hit [clk] + UChar_t vcM; //! maximum col + UChar_t vrM; //! maximum row + UChar_t viM; //! index of maximum signal in the projection + UShort_t vyM; //! bit map for cluster topology classification + std::vector<Double_t> vs; //! working copy of signals from cluster + std::vector<Double_t> vse; //! working copy of signal errors from cluster + std::vector<Char_t> vt; //! working copy of signal relative timing + std::vector<Double_t> vx; //! working copy of signal relative positions + std::vector<Double_t> vxe; //! working copy of signal relative position errors static Float_t fgCorrXdx; //! step of the discretized correction LUT - static Float_t fgCorrXval[2][NBINSCORRX]; //! discretized correction LUT + static Float_t fgCorrXval[3][NBINSCORRX]; //! discretized correction LUT static Float_t fgCorrYval[NBINSCORRY][2]; //! discretized correction params + static Float_t fgCorrRcXval[2][NBINSCORRX]; //! discretized correction LUT + static Float_t fgCorrRcXbiasXval[3][NBINSCORRX]; //! discretized correction LUT static Double_t fgDT[3]; //! FASP delay wrt signal static TGraphErrors* fgEdep; //! data handler for cluster PRF static TF1* fgPRF; //! fitter for cluster PRF static TGraphErrors* fgT; //! data handler for cluster TRF ClassDef(CbmTrdModuleRecT, - 1) // Triangular pad module; Cluster finding and hit reconstruction algorithms + 2) // Triangular pad module; Cluster finding and hit reconstruction algorithms }; void CbmTrdModuleRecT::Config(Bool_t v, Bool_t d) @@ -111,4 +226,10 @@ void CbmTrdModuleRecT::Config(Bool_t v, Bool_t d) CLRBIT(fConfigMap, kDraw); printf("CbmTrdModuleRecT::Draw[%c]\n", CDRAW() ? 'y' : 'n'); } + +Bool_t CbmTrdModuleRecT::IsOpenRight() const +{ + Int_t nR = vs.size() - 1 - viM; + return (nR % 2 && IsMaxTilt()) || (!(nR % 2) && !IsMaxTilt()); +} #endif diff --git a/reco/detectors/trd/CbmTrdRecoLinkDef.h b/reco/detectors/trd/CbmTrdRecoLinkDef.h index c0f2d416da957939c564ef5a1fc6ebb5067035b9..92169034aee6d743659257453822b1a44d706fee 100644 --- a/reco/detectors/trd/CbmTrdRecoLinkDef.h +++ b/reco/detectors/trd/CbmTrdRecoLinkDef.h @@ -1,6 +1,6 @@ /* Copyright (C) 2020 Institut fuer Kernphysik, Goethe-Universitaet Frankfurt, Frankfurt SPDX-License-Identifier: GPL-3.0-only - Authors: Pascal Raisig [committer] */ + Authors: Pascal Raisig [committer], Alexandru Bercuci */ // $Id: TrdRecoLinkDef.h $ @@ -17,6 +17,7 @@ #pragma link C++ class CbmTrdModuleRec + ; #pragma link C++ class CbmTrdModuleRecR + ; #pragma link C++ class CbmTrdModuleRecT + ; +#pragma link C++ class CbmTrdDigiRec + ; #pragma link C++ class CbmTrdClusterizerFastQa + ; #pragma link C++ class CbmTrdHitDensityQa + ; diff --git a/sim/detectors/trd/CbmTrdModuleSimT.cxx b/sim/detectors/trd/CbmTrdModuleSimT.cxx index 94a181046e06010616a109e6378b24632a598f0d..53d9c63723fea2201f158fade6ad25da19dd1384 100644 --- a/sim/detectors/trd/CbmTrdModuleSimT.cxx +++ b/sim/detectors/trd/CbmTrdModuleSimT.cxx @@ -92,22 +92,36 @@ Bool_t CbmTrdModuleSimT::MakeDigi(CbmTrdPoint* point, Double_t time, Bool_t TR) // General processing on the MC point Double_t ELossTR(0.), ELossdEdX(point->GetEnergyLoss()); - if (fRadiator && TR) { - // nofElectrons++; - if ( - fRadiator->LatticeHit( - point)) { // electron has passed lattice grid (or frame material) befor reaching the gas volume -> TR-photons have been absorbed by the lattice grid - // nofLatticeHits++; + if (IsLabMeasurement()) { + ELossdEdX = 0.; + if (IsFeCalib()) { + //E[keV]=5.895; // 55Fe, Ka (89%) + //E[keV]=6.492; // 55Fe, Kb (11%) + ELossTR = gRandom->Uniform() > 0.89 ? 6.492 : 5.895; } - else if (gout[2] >= gin[2]) { //electron has passed the radiator - TVector3 mom; - point->Momentum(mom); - ELossTR = fRadiator->GetTR(mom); + else { // TODO implement Xrays spectrum + ; //if (fRadiator) ELossTR = fRadiator->GetXray(mom)*1.e6; // keV + } + if (VERBOSE) { + printf("CbmTrdModuleSimT::MakeDigi for %s ...\n", (IsFeCalib() ? "55Fe" : "X-rays")); + if (ELossTR > 0) LOG(info) << " Ex " << ELossTR << " keV"; + } + } + else { + if (fRadiator && TR) { + // nofElectrons++; + if ( + fRadiator->LatticeHit( + point)) { // electron has passed lattice grid (or frame material) befor reaching the gas volume -> TR-photons have been absorbed by the lattice grid + // nofLatticeHits++; + } + else if (gout[2] >= gin[2]) { //electron has passed the radiator + TVector3 mom; + point->Momentum(mom); + ELossTR = fRadiator->GetTR(mom); + } } } - //ELossTR=5.895; // 55Fe, Ka (89%) - //ELossTR=6.492; // 55Fe, Kb (11%) - //ELossdEdX = gRandom->Gaus(ELossdEdX, ); // compute track length in the gas volume Double_t trackLength(0.), txy(0.); @@ -274,7 +288,8 @@ Bool_t CbmTrdModuleSimT::MakeDigi(CbmTrdPoint* point, Double_t time, Bool_t TR) //ELossTR = gRandom->Gaus(ELossTR, ); // account for gain uncertainty ELossTR = fChmbPar->EkevFC(ELossTR); // convert Edep [keV] to collected charge [fC] - ScanPadPlane(ain, tdrift * diffx, ELossTR, time + point->GetTime() + tdrift); + if (!IsLabMeasurement()) tdrift += time + point->GetTime(); + ScanPadPlane(ain, tdrift * diffx, ELossTR, tdrift); } return kTRUE; } @@ -530,7 +545,7 @@ void CbmTrdModuleSimT::AddDigi(Int_t address, Double_t* charge, Double_t time /* digi = new CbmTrdDigi(address, charge[0], charge[1], ULong64_t(TMath::Ceil(time))); digi->SetAddressModule(fModAddress); // may not be needed in the future digiMatch = new CbmMatch(); - Double_t weighting = 1; + Double_t weighting = fChmbPar->EfCkeV(charge[0] * 0.1); // save th. energy which is seen by pads; digiMatch->AddLink(CbmLink(weighting, fPointId, fEventId, fInputId)); //digi->SetMatch(digiMatch); diff --git a/sim/detectors/trd/CbmTrdModuleSimT.h b/sim/detectors/trd/CbmTrdModuleSimT.h index 7224d7e653e8d73bcde0ad85cb1c2885fd856ef7..dbf03facf48bc251ef9c48888234570a99543e60 100644 --- a/sim/detectors/trd/CbmTrdModuleSimT.h +++ b/sim/detectors/trd/CbmTrdModuleSimT.h @@ -11,10 +11,17 @@ class CbmTimeSlice; class CbmTrdFASP; class CbmTrdTrianglePRF; class CbmTrdParSetAsic; -/** - * \brief Simulation module implementation for triangular pad geometry - * \author Alex Bercuci <abercuci@niham.nipne.ro> - **/ +/** @class CbmTrdModuleSimT + ** @brief Simulation module implementation for TRD-2D physics and FEE + ** @author Alex Bercuci <abercuci@niham.nipne.ro> + ** @since 01.02.2019 + ** @date 10.10.2021 + ** + ** The class is steered via CbmTrdDigitizer by looping over all MC points + ** generated during track propagation. The class can be used to digitize MC + ** output but also simulate laboratory set-ups (\sa SetLabMeasurement()) like + ** 55Fe (\sa SetFeCalib()) or X-rays (\sa SetFeCalib(kFALSE)) + **/ class CbmTrdModuleSimT : public CbmTrdModuleSim { public: enum ECbmTrdModuleSimT