StRoot  1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
StiTpcDetectorBuilder.cxx
1 #include <algorithm>
2 #include <assert.h>
3 #include <stdio.h>
4 #include <stdexcept>
5 #include "StDbUtilities/StTpcLocalCoordinate.hh"
6 #include "StDbUtilities/StTpcCoordinateTransform.hh"
7 #include "StTpcDb/StTpcDb.h"
8 #include "Sti/StiPlanarShape.h"
9 #include "Sti/StiCylindricalShape.h"
10 #include "Sti/StiMaterial.h"
11 #include "Sti/StiPlacement.h"
12 #include "Sti/StiDetector.h"
13 #include "Sti/Base/Factory.h"
14 #include "Sti/StiToolkit.h"
15 #include "Rtypes.h"
16 #include "StDetectorDbMaker/StiTpcInnerHitErrorCalculator.h"
17 #include "StDetectorDbMaker/StiTpcOuterHitErrorCalculator.h"
18 #include "StiTpcDetectorBuilder.h"
20 #include "StDetectorDbMaker/StDetectorDbTpcRDOMasks.h"
21 #include "StDetectorDbMaker/St_tpcPadConfigC.h"
22 #include "StDbUtilities/StCoordinates.hh"
23 #include "StTpcDb/StTpcDb.h"
24 #include "StMatrixD.hh"
25 #include "StDetectorDbMaker/St_tpcAnodeHVavgC.h"
26 #include "StDetectorDbMaker/St_tpcPadGainT0BC.h"
27 //#define TPC_IDEAL_GEOM
28 
29 std::set<StiTpcDetectorBuilder::StiLayer> StiTpcDetectorBuilder::sStiLayers{};
30 
31 
32 StiTpcDetectorBuilder::StiTpcDetectorBuilder(Bool_t active, bool active_iTpc)
33  : StiDetectorBuilder("Tpc",active), _active_iTpc(active_iTpc) {}
34 
35 StiTpcDetectorBuilder::~StiTpcDetectorBuilder() {}
36 
46 {
47  cout << "StiTpcDetectorBuilder::buildDetectors() -I- Started" << endl;
48  assert(gStTpcDb);
49  useVMCGeometry();
50  cout << "StiTpcDetectorBuilder::buildDetectors() -I- Done" << endl;
51 }
52 //________________________________________________________________________________
53 void StiTpcDetectorBuilder::useVMCGeometry()
54 {
55  Int_t debug = 0;
56 
57  if (debug>1) StiVMCToolKit::SetDebug(1);
58  cout << "StiTpcDetectorBuilder::buildDetectors() -I- Use VMC geometry" << endl;
59  SetCurrentDetectorBuilder(this);
60 
61  // Get Materials
62  TGeoVolume *volT = gGeoManager->GetVolume("TPAD");
63  if (! volT) volT = gGeoManager->GetVolume("tpad");
64  assert(volT);
65  TGeoMaterial *mat = volT->GetMaterial();
66  assert(mat);
67  if (debug>1) mat->Print();
68  Double_t PotI = StiVMCToolKit::GetPotI(mat);
69  if (debug>1) cout << "PotI " << PotI << endl;
70  _gasMat = add(new StiMaterial(mat->GetName(),
71  mat->GetZ(),
72  mat->GetA(),
73  mat->GetDensity(),
74  mat->GetDensity()*mat->GetRadLen(),
75  PotI));
76 
77  // Create active Sti volumes for TPC sensitive layers
78  StiTpcDetectorBuilder::buildStiLayerMap();
79 
80  for(const StiLayer& stiLayer : sStiLayers)
81  {
82  StiPlanarShape* pShape = constructTpcPadrowShape(stiLayer);
83  StiDetector* pDetector = constructTpcPadrowDetector(stiLayer, pShape);
84 
85  add(stiLayer.sti_padrow_id, stiLayer.sti_sector_id, pDetector);
86  if (debug>1) cout << *pDetector << endl;
87  }
88 
89  // Create inactive Sti volumes by averaging material in TPC inner and outer field cages
90  const VolumeMap_t TpcVolumes[] = {
91  {"TIFC","Inner Field Cage","HALL_1/CAVE_1/TPCE_1/TIFC_1","",""},
92  {"TOFC","Inner Field Cage","HALL_1/CAVE_1/TPCE_1/TOFC_1","",""},
93  {"TIFC","Inner Field Cage","HALL_1/CAVE_1/TpcRefSys_1/TPCE_1/TIFC_1","",""},
94  {"TOFC","Inner Field Cage","HALL_1/CAVE_1/TpcRefSys_1/TPCE_1/TOFC_1","",""},
95  };
96 
97  TString check_path("HALL_1/CAVE_1/TpcRefSys_1/TPCE_1");
98  bool newRefSystem = gGeoManager->cd(check_path) ? true : false;
99 
100  for (Int_t i = 0; i < 4; i++) {
101  TString path = TpcVolumes[i].path;
102 
103  if ( newRefSystem && !path.Contains("TpcRefSys")) continue;
104  if (!newRefSystem && path.Contains("TpcRefSys")) continue;
105  if (!gGeoManager->cd(path)) {
106  LOG_WARN << "Skipping non-existing geometry path " << path << endm;
107  continue;
108  }
109 
110  TGeoNode *nodeT = gGeoManager->GetCurrentNode();
111  StiVMCToolKit::LoopOverNodes(nodeT, path, TpcVolumes[i].name, MakeAverageVolume);
112  }
113 }
114 
115 
116 StiDetector* StiTpcDetectorBuilder::constructTpcPadrowDetector(StiLayer stiLayer, StiPlanarShape* pShape) const
117 {
118  int tpc_sector_id = stiLayer.tpc_sector();
119  int tpc_padrow_id = stiLayer.tpc_padrow();
120 
121  StDetectorDbTpcRDOMasks *s_pRdoMasks = StDetectorDbTpcRDOMasks::instance();
122  St_tpcPadConfigC& tpcPadCfg = *St_tpcPadConfigC::instance();
123  UInt_t nRows = tpcPadCfg.numberOfRows(tpc_sector_id);// Only sensitive detectors
124  UInt_t nInnerPadrows = tpcPadCfg.numberOfInnerRows(tpc_sector_id);
125  //Nominal pad row information.
126  // create properties shared by all sectors in this padrow
127  float fRadius = tpcPadCfg.radialDistanceAtRow(tpc_sector_id, tpc_padrow_id);
128  StTpcCoordinateTransform transform(gStTpcDb);
129  StMatrixD local2GlobalRotation;
130  StMatrixD unit(3,3,1);
131  // The length of the Sti layer shape is used to place it in the rigth position
132  // along z. We have to multiply by 0.5 to revert the effect of the old
133  // implementation bug when the length was doubled
134  Double_t dZ = pShape->getHalfDepth()*0.5;
135 
136  //Retrieve position and orientation of the TPC pad rows from the database.
137  StTpcLocalSectorDirection dirLS[3];
138  dirLS[0] = StTpcLocalSectorDirection(1.,0.,0.,tpc_sector_id,tpc_padrow_id);
139  dirLS[1] = StTpcLocalSectorDirection(0.,1.,0.,tpc_sector_id,tpc_padrow_id);
140  dirLS[2] = StTpcLocalSectorDirection(0.,0.,1.,tpc_sector_id,tpc_padrow_id);
141  local2GlobalRotation = unit;
142  for (Int_t i = 0; i < 3; i++) {
143  // if (debug>1) cout << "dirLS\t" << dirLS[i] << endl;
144 #ifndef TPC_IDEAL_GEOM
145  StTpcLocalDirection dirL;
147  transform(dirLS[i],dirLSA);// if (debug>1) cout << "dirLSA\t" << dirLSA << endl;
148  transform(dirLSA,dirL); // if (debug>1) cout << "dirL\t" << dirL << endl;
149  StGlobalDirection dirG;
150  transform(dirL,dirG);// if (debug>1) cout << "dirG\t" << dirG << endl;
151 #else
152  StTpcLocalDirection dirG;
153  transform(dirLS[i],dirG);
154 #endif
155  local2GlobalRotation(i+1,1) = dirG.position().x();
156  local2GlobalRotation(i+1,2) = dirG.position().y();
157  local2GlobalRotation(i+1,3) = dirG.position().z();
158  }
159  // if (debug>1) cout << "Local2GlobalRotation = " << local2GlobalRotation << endl;
160  Double_t y = transform.yFromRow(tpc_sector_id, tpc_padrow_id);
161  StTpcLocalSectorCoordinate lsCoord(0., y, dZ, tpc_sector_id, tpc_padrow_id);// if (debug>1) cout << lsCoord << endl;
162 #ifndef TPC_IDEAL_GEOM
164  transform(lsCoord,lsCoordA);// if (debug>1) cout << lsCoordA << endl;
165  StGlobalCoordinate gCoord;
166  transform(lsCoordA, gCoord);// if (debug>1) cout << gCoord << endl;
167 #else // Ideal geom
168  StTpcLocalCoordinate gCoord;
169  transform(lsCoord, gCoord);
170 #endif
171  // unit vector normal to the pad plane
172  StThreeVectorD centerVector(gCoord.position().x(),gCoord.position().y(),gCoord.position().z());
173  StThreeVectorD normalVector(local2GlobalRotation(2,1),
174  local2GlobalRotation(2,2),
175  local2GlobalRotation(2,3));
176  Double_t prod = centerVector*normalVector;
177  if (prod < 0) normalVector *= -1;
178  Double_t phi = centerVector.phi();
179  Double_t phiD = normalVector.phi();
180  Double_t r = centerVector.perp();
181  StiPlacement *pPlacement = new StiPlacement;
182  Double_t zc = 0;
183 
184  if ( stiLayer.represents_only(StiLayer::West) ) zc = 2*dZ;
185  if ( stiLayer.represents_only(StiLayer::East) ) zc = -2*dZ;
186 
187  pPlacement->setZcenter(zc);
188  pPlacement->setLayerRadius(fRadius);
189  pPlacement->setLayerAngle(phi);
190  pPlacement->setRegion(StiPlacement::kMidRapidity);
191  pPlacement->setNormalRep(phiD, r*TMath::Cos(phi-phiD), r*TMath::Sin(phi-phiD));
192  TString name = Form("Tpc/Padrow_%d/Sector_%d", stiLayer.sti_padrow_id, stiLayer.sti_sector_id);
193  // fill in the detector object and save it in our vector
194  StiDetector *pDetector = _detectorFactory->getInstance();
195  pDetector->setName(name.Data());
196  pDetector->setIsOn(kTRUE);
197  Bool_t west = kTRUE;
198  Bool_t east = kTRUE;
199  if (nRows == 45) { // ! iTpx
200 
201  int tpc_sector_id_west = stiLayer.tpc_sector(StiLayer::West);
202  int tpc_sector_id_east = stiLayer.tpc_sector(StiLayer::East);
203 
204  Int_t iRdo = s_pRdoMasks->rdoForPadrow(tpc_padrow_id);
205  Bool_t west = tpc_sector_id_west > 0 && s_pRdoMasks->isOn(tpc_sector_id_west, iRdo);
206  Bool_t east = tpc_sector_id_east > 0 && s_pRdoMasks->isOn(tpc_sector_id_east, iRdo);
207 
208  if (west) {
209  west = St_tpcAnodeHVavgC::instance()->livePadrow(tpc_sector_id_west,tpc_padrow_id) &&
210  St_tpcPadGainT0BC::instance()->livePadrow(tpc_sector_id_west,tpc_padrow_id);
211  }
212  if (east) {
213  east = St_tpcAnodeHVavgC::instance()->livePadrow(tpc_sector_id_east,tpc_padrow_id) &&
214  St_tpcPadGainT0BC::instance()->livePadrow(tpc_sector_id_east,tpc_padrow_id);
215  }
216  }
217 
218  StiIsActiveFunctor* activator = nullptr;
219 
220  if ( tpcPadCfg.isiTpcPadRow(tpc_sector_id, tpc_padrow_id) ) {
221  //pDetector->setGroupId(kiTpcId);
222  pDetector->setGroupId(kTpcId); // Y. Fisyak and I. Chakaberia approach is not to use kiTpcId
223  activator = _active_iTpc ? new StiTpcIsActiveFunctor(true,west,east) :
224  new StiTpcIsActiveFunctor(false,west,east);
225  }
226  else {
227  pDetector->setGroupId(kTpcId);
228  activator = new StiTpcIsActiveFunctor(_active,west,east);
229  }
230 
231  pDetector->setIsActive(activator);
232  pDetector->setIsContinuousMedium(kTRUE);
233  pDetector->setIsDiscreteScatterer(kFALSE);
234  pDetector->setMaterial(_gasMat);
235  pDetector->setGas(_gasMat);
236  pDetector->setShape(pShape);
237  pDetector->setPlacement(pPlacement);
238 
239  if (tpc_padrow_id <= nInnerPadrows)
240  pDetector->setHitErrorCalculator(StiTpcInnerHitErrorCalculator::instance());
241  else
242  pDetector->setHitErrorCalculator(StiTpcOuterHitErrorCalculator::instance());
243 
244  pDetector->setKey(1,stiLayer.sti_padrow_id);
245  pDetector->setKey(2,stiLayer.sti_sector_id);
246 
247  return pDetector;
248 }
249 
250 
251 StiPlanarShape* StiTpcDetectorBuilder::constructTpcPadrowShape(StiLayer stiLayer) const
252 {
253  int tpc_sector_id = stiLayer.tpc_sector();
254  int tpc_padrow_id = stiLayer.tpc_padrow();
255 
256  St_tpcPadConfigC& tpcPadCfg = *St_tpcPadConfigC::instance();
257  UInt_t nInnerPadrows = tpcPadCfg.numberOfInnerRows(tpc_sector_id);
258 
259  TString name = Form("Tpc/Padrow_%d/Sector_%d", stiLayer.sti_padrow_id, stiLayer.sti_sector_id);
260  StiPlanarShape* pShape = new StiPlanarShape;
261 
262  if (!pShape)
263  throw runtime_error("StiTpcDetectorBuilder::buildDetectors() - FATAL - pShape==0||ofcShape==0");
264 
265  Double_t dZ = 0;
266  if(tpc_padrow_id <= nInnerPadrows) {
267  pShape->setThickness(tpcPadCfg.innerSectorPadLength(tpc_sector_id));
268  dZ = tpcPadCfg.innerSectorPadPlaneZ(tpc_sector_id);
269  }
270  else {
271  pShape->setThickness(tpcPadCfg.outerSectorPadLength(tpc_sector_id));
272  dZ = tpcPadCfg.outerSectorPadPlaneZ(tpc_sector_id);
273  }
274 
275  // Check if stiLayer represents only one half of TPC layer
276  if ( stiLayer.represents_only(StiLayer::West) ||
277  stiLayer.represents_only(StiLayer::East) )
278  {
279  dZ *= 0.5;
280  }
281 
282  // The length is doubled to match the old implementation where the value
283  // depended on the number of TPC sectors. Without the factor 2 we loose prompt
284  // hits which can be outside of the physical volume
285  pShape->setHalfDepth(dZ*2);
286  pShape->setHalfWidth(tpcPadCfg.PadPitchAtRow(tpc_sector_id, tpc_padrow_id) *
287  tpcPadCfg.numberOfPadsAtRow(tpc_sector_id, tpc_padrow_id) / 2.);
288  pShape->setName(name.Data());
289 
290  if (StiVMCToolKit::Debug()>1) cout << *pShape << endl;
291 
292  return pShape;
293 }
294 
295 
296 
297 double StiTpcDetectorBuilder::StiLayer::radial_distance() const
298 {
299  St_tpcPadConfigC& tpcPadCfg = *St_tpcPadConfigC::instance();
300 
301  double delta = 0;
302 
303  if (sti_split_in_half)
304  delta = represents_only(StiLayer::East) ? +0.1 : (represents_only(StiLayer::West) ? -0.1 : 0);
305 
306  return tpcPadCfg.radialDistanceAtRow(tpc_sector(), tpc_padrow()) + delta;
307 }
308 
309 
310 
311 bool StiTpcDetectorBuilder::StiLayer::operator< (const StiLayer& other) const
312 {
313  double radius = radial_distance();
314  double radius_other = other.radial_distance();
315 
316  bool result =
317  ( radius < radius_other ) ||
318  ( radius == radius_other && sti_sector_id < other.sti_sector_id );
319 
320  return result;
321 }
322 
323 
324 
325 std::ostream& operator<<(std::ostream& os, const StiTpcDetectorBuilder::StiLayer& stiLayer)
326 {
327  St_tpcPadConfigC& tpcPadCfg = *St_tpcPadConfigC::instance();
328 
329  double radius = tpcPadCfg.radialDistanceAtRow(stiLayer.tpc_sector(), stiLayer.tpc_padrow());
330 
331  os << radius << ",\t" << stiLayer.radial_distance() << ";\t"
332  << stiLayer.tpc_sector_id[0] << ",\t" << stiLayer.tpc_padrow_id[0] << ";\t"
333  << stiLayer.tpc_sector_id[1] << ",\t" << stiLayer.tpc_padrow_id[1] << "\t-->\t"
334  << stiLayer.sti_sector_id << ",\t" << stiLayer.sti_padrow_id;
335 
336  return os;
337 }
338 
339 
340 
341 std::pair<int, int> StiTpcDetectorBuilder::toStiLayer(const int tpc_sector, const int tpc_padrow)
342 {
343  auto find_tpc_sector = [tpc_sector, tpc_padrow](const StiLayer& sl)
344  {
345  StiLayer::TpcHalf half = (tpc_sector <= 12 ? StiLayer::West : StiLayer::East);
346  return sl.tpc_sector_id[half] == tpc_sector && sl.tpc_padrow_id[half] == tpc_padrow;
347  };
348 
349  auto stiLayerIter = std::find_if(sStiLayers.begin(), sStiLayers.end(), find_tpc_sector);
350 
351  return stiLayerIter != sStiLayers.end() ?
352  std::make_pair(stiLayerIter->sti_sector_id, stiLayerIter->sti_padrow_id) :
353  std::pair<int, int>(-1, -1);
354 }
355 
356 
357 
358 void StiTpcDetectorBuilder::buildStiLayerMap()
359 {
360  St_tpcPadConfigC& tpcPadCfg = *St_tpcPadConfigC::instance();
361 
362  sStiLayers.clear();
363 
364  for(int sector = 1; sector <= 24; sector++)
365  {
366  for(int row = 1; row <= tpcPadCfg.numberOfRows(sector); row++)
367  {
368  std::set<StiLayer>::iterator stiLayerIter;
369  bool inserted;
370  std::tie(stiLayerIter, inserted) = sStiLayers.insert( StiLayer(sector, row) );
371 
372  if (!inserted) stiLayerIter->update_tpc_id(sector, row);
373  }
374  }
375 
376  // Now we loop over the sorted (by radius) set of StiLayers and assign a
377  // corresponding padrow ID to each layer
378  auto prevStiLayer = sStiLayers.begin();
379  auto currStiLayer = sStiLayers.begin();
380 
381  for ( ; currStiLayer != sStiLayers.end(); ++currStiLayer)
382  {
383  currStiLayer->sti_padrow_id = prevStiLayer->sti_padrow_id;
384 
385  if (currStiLayer->radial_distance() != prevStiLayer->radial_distance())
386  currStiLayer->sti_padrow_id++;
387 
388  prevStiLayer = currStiLayer;
389  }
390 
391 }
int tpc_sector_id[2]
East and/or West if available.
int tpc_padrow_id[2]
East and/or West if available.
function object for determine a TPC padrow&#39;s active regions
virtual Abstract * getInstance()=0
Get a pointer to instance of objects served by this factory.
virtual void buildDetectors(StMaker &s)
function object for determine a detector&#39;s active regions
Abstract interface for a STI toolkit.
bool sti_split_in_half
Split Sti layer in East and West halves.
bool _active_iTpc
Option to use iTPC hits in Sti tracking. By default hits are not used in Sti tracking.
void setName(const string &newName)
Set the name of the object.
Definition: Named.cxx:15