KaliVeda
Toolkit for HIC analysis
INDRAGeometryBuilder.cpp
1 //Created by KVClassFactory on Wed Feb 1 11:09:41 2012
2 //Author: John Frankland,,,
3 
4 #include "INDRAGeometryBuilder.h"
5 #include "KVTarget.h"
6 #include "KVUnits.h"
7 #include "TEnv.h"
8 #include "TMath.h"
9 #include "TString.h"
10 #include "TGeoMedium.h"
11 #include "TRotation.h"
12 #include "TGeoMatrix.h"
13 #include "TGeoManager.h"
14 #include "TGeoCompositeShape.h"
15 #include "TGeoEltu.h"
16 #include "KVINDRA.h"
17 #include "KVDataSet.h"
18 
19 using namespace std;
20 
21 //#define DEBUG 1
22 
24 
25 
26 
42 void INDRAGeometryBuilder::read_indra_struct_file()
43 {
44  // Read infos in dataset file
45  //
46  // indra-struct.env
47  //
48  // or alternatively, by defining the variable
49  //
50  // [dataset].INDRA.StructureFile: [name of dataset]
51  //
52  // use the file from another dataset.
53  //
54  // These files were previously used for all geometry specifications;
55  // now they mainly serve to define which detectors/rings are present,
56  // and change the default nominal thickness of silicon detectors or
57  // define the default gas pressures in the ionization chambers
58 
59  TString alt_dataset = GetDataSetEnv(fDataSet, "INDRA.StructureFile", "");
60  if(alt_dataset=="") alt_dataset=fDataSet;
61 
62  auto path = KVDataSet::GetFullPathToDataSetFile(alt_dataset,"indra-struct.env");
63 
64  Info("read_indra_struct_file", "Reading INDRA structure from file : %s", path.Data());
65  fStrucInfos.ReadFile(path, kEnvAll);
66 
67  auto run_index_multiplier = GetDataSetEnv(alt_dataset, "DataSet.RunFileIndexMultiplier.raw", 1);
68 
69  //test if additional geometrical specifications for certain runs exists
70  KVString lruns = fStrucInfos.GetValue("AddOnForRuns", "");
71  if (lruns != "") {
72  lruns.Begin(",");
73  while (!lruns.End()) {
74  KVString sruns = lruns.Next();
75  KVNumberList nlr(sruns.Data());
76  //the current run needs specific geometry
77  if (nlr.Contains(fCurrentRun*run_index_multiplier))
78  {
79  path = fStrucInfos.GetValue(sruns.Data(), "");
80  Info("BuildGeometry", "Additional geometry for run=%d in file #%s#", fCurrentRun, path.Data());
81  path = KVDataSet::GetFullPathToDataSetFile(alt_dataset,path.Data());
82  fStrucInfos.ReadFile(path, kEnvChange);
83  }
84  }
85  }
86 
87  // to be used as name of KVINDRA object
88  SetName(fStrucInfos.GetValue("INDRA.Name", ""));
89  SetTitle(fStrucInfos.GetValue("INDRA.Title", ""));
90 
91  KVString layers = fStrucInfos.GetValue("INDRA.Layers", "");
92  layers.Begin(" ");
93  while (!layers.End()) read_layer_infos(layers.Next());
94 
95 }
96 
97 
98 
101 
103 {
104  // read infos on layer 'name' in file "$KVROOT/KVFiles/data/indra-struct.[dataset].env"
105 
106  Int_t number = fStrucInfos.GetValue(Form("INDRA.Layer.%s.Number", name), 0);
107  Info("read_layer_infos", "Building layer %d:%s", number, name);
108  KVNumberList rings = fStrucInfos.GetValue(Form("INDRA.Layer.%s.Rings", name), "");
109  rings.Begin();
110  while (!rings.End()) {
111  Int_t ring_num = rings.Next();
112  TString prefix = Form("INDRA.Layer.%s.Ring.%d", name, ring_num);
113  read_ring_infos(ring_num, prefix);
114  }
115 }
116 
117 
118 
121 
122 void INDRAGeometryBuilder::read_ring_infos(Int_t ring_number, const Char_t* prefix)
123 {
124  // read infos on ring in file "$KVROOT/KVFiles/data/indra-struct.[dataset].env"
125 
126  Info("read_ring_infos", "Building ring %d (%s)", ring_number, prefix);
127 
128  Int_t ntel = fStrucInfos.GetValue(Form("%s.Ntel", prefix), 0);
129  Int_t step = fStrucInfos.GetValue(Form("%s.Step", prefix), 1);
130  Int_t num_first = fStrucInfos.GetValue(Form("%s.Nfirst", prefix), 1);
131  Double_t thmin = fStrucInfos.GetValue(Form("%s.ThMin", prefix), 0.0);
132  Double_t thmax = fStrucInfos.GetValue(Form("%s.ThMax", prefix), 0.0);
133  Double_t phi_0 = fStrucInfos.GetValue(Form("%s.Phi0", prefix), 0.0);
134  Double_t dphi = fStrucInfos.GetValue(Form("%s.Dphi", prefix), -1.0);
135  dphi = (dphi < 0. ? 360. / ntel : dphi);
136  KVNumberList absent = fStrucInfos.GetValue(Form("%s.Absent", prefix), "");
137 
138  Double_t phi = phi_0;
139  UInt_t counter = num_first;
140  auto det_props = read_telescope_infos(prefix, ring_number, counter, ntel, thmin, thmax, phi);
141 
142  for (int i = 0; i < ntel; i++) {
143  if (!absent.Contains(counter)) {
144  for (auto& d : det_props) detector_map[d.name] = d;
145  }
146  phi = (phi + dphi > 360. ? (phi + dphi - 360.) : (phi + dphi));
147  counter += step;
148  if (i + 1 < ntel) det_props = read_telescope_infos(prefix, ring_number, counter, ntel, thmin, thmax, phi);
149  }
150 }
151 
152 
153 
156 
157 std::vector<INDRAGeometryBuilder::detector_properties>
159  const Char_t* prefix, Int_t ring, Int_t module, Int_t ntel,
160  double thmin, double thmax, double phi)
161 {
162  // read telescope infos in file "$KVROOT/KVFiles/data/indra-struct.[dataset].env"
163 
164  KVString telescopes = fStrucInfos.GetValue(Form("%s.Telescope", prefix), "");
165  telescopes.Begin(" ");
166  KVString name;
167  while (!telescopes.End()) {
168  name = telescopes.Next();
169  KVNumberList mods = fStrucInfos.GetValue(Form("%s.Telescope.%s.Modules", prefix, name.Data()), "1-100");
170  if (mods.Contains(module)) break;
171  }
172 
173  KVString detectors = fStrucInfos.GetValue(Form("INDRA.Telescope.%s.Detectors", name.Data()), "");
174  double aziwidth = fStrucInfos.GetValue(Form("INDRA.Telescope.%s.AziWidth", name.Data()), 0.0);
175  double phimin = phi-0.5*aziwidth;
176  double phimax = phi+0.5*aziwidth;
177 
178  detectors.Begin(" ");
179  Int_t idet = 1;
180  std::vector<detector_properties> det_props;
181  while (!detectors.End()) {
182  KVString det = detectors.Next();
183  det.Begin("(,)");
184  KVString dettype = det.Next();
185 
186  // set flag if PHOSwich ring is used
187  if (dettype == "PHOS") fWithPhoswich = kTRUE;
188 
189  Double_t detthick = det.Next().Atof();
190  if (dettype == "SILI" || dettype == "SI75")
191  det_props.push_back(detector_properties{Form("%s_%02d", dettype.Data(), ring), detthick, ring, 0, {thmin, thmax}, {phimin, phimax}, true});
192  else if (dettype == "PHOS") {
193  // for phoswich thicknesses are given as PHOS(0.05,25)
194  // for geometry definition, '25cm' layer is set as active layer - so take second thickness value
195  detthick = det.Next().Atof();
196  det_props.push_back(detector_properties{Form("%s_%02d", dettype.Data(), module), detthick, 1, module, {thmin, thmax}, {phimin, phimax}, true});
197  }
198  else if (dettype == "SI")
199  // silicon detector thicknesses are given in microns
200  det_props.push_back(detector_properties{Form("%s_%02d%02d", dettype.Data(), ring, module), detthick * KVUnits::um, ring, module, {thmin, thmax}, {phimin, phimax}, true});
201  else
202  det_props.push_back(detector_properties{Form("%s_%02d%02d", dettype.Data(), ring, module), detthick, ring, module, {thmin, thmax}, {phimin, phimax}, true});
203 
204  idet++;
205  }
206  return det_props;
207 }
208 
209 
210 
215 
217 {
218  // calculate offset in X and Y
219  // correct coordinates for offset
220  // return offset TGeoTranslation
221 
222  offX = offY = 0;
223  for (int i = 0; i < 8; i++) {
224  offX += coo[2 * i];
225  offY += coo[2 * i + 1];
226  }
227  offX /= 8.;
228  offY /= 8.;
229  for (int i = 0; i < 8; i++) {
230  coo[2 * i] -= offX;
231  coo[2 * i + 1] -= offY;
232  }
233 }
234 
235 
236 
239 
241  : fDataSet(_data_set), fCurrentRun(current_run)
242 {
243  // Default constructor
244  fEtalonVol = 0;
245 }
246 
247 
248 
255 
257 {
258  // Given an array of ncoords points frontcoords[ncoords] which lie in a plane
259  // calculate the corresponding points on a parallel plane which is
260  // at a distance from the origin which is greater by depth
261  // (distance plane-origin = length of normal to plane passing through origin)
262  // 'normal' is vector point of intersection plane-normal to origin
263 
264  Double_t planeDist = normal.Mag();//distance original plane-origin
265  for (int i = 0; i < 4; i++) {
266  Double_t rap = (planeDist + depth) / planeDist;
267  backcoords[i] = rap * frontcoords[i];
268  }
269 }
270 
271 
272 
276 
278 {
279  // Read infos in CAO file for this detector.
280  // We look for a TEnv file with name "detname.cao"
281 
282  TEnv infos;
283  TString path = Form("%s.cao", detname);
284  SearchKVFile(path.Data(), path, "data");
285  infos.ReadFile(path, kEnvAll);
286 
287  Double_t unit_converter = 0.1;// distances in file given in mm: convert to cm
288 
289  fInnerFront[0].SetX(infos.GetValue("INNER.A.X", 0.0)*unit_converter);
290  fInnerFront[0].SetY(infos.GetValue("INNER.A.Y", 0.0)*unit_converter);
291  fInnerFront[0].SetZ(infos.GetValue("INNER.A.Z", 0.0)*unit_converter);
292  fInnerFront[3].SetX(infos.GetValue("INNER.B.X", 0.0)*unit_converter);
293  fInnerFront[3].SetY(infos.GetValue("INNER.B.Y", 0.0)*unit_converter);
294  fInnerFront[3].SetZ(infos.GetValue("INNER.B.Z", 0.0)*unit_converter);
295  fInnerFront[2].SetX(infos.GetValue("INNER.C.X", 0.0)*unit_converter);
296  fInnerFront[2].SetY(infos.GetValue("INNER.C.Y", 0.0)*unit_converter);
297  fInnerFront[2].SetZ(infos.GetValue("INNER.C.Z", 0.0)*unit_converter);
298  fInnerFront[1].SetX(infos.GetValue("INNER.D.X", 0.0)*unit_converter);
299  fInnerFront[1].SetY(infos.GetValue("INNER.D.Y", 0.0)*unit_converter);
300  fInnerFront[1].SetZ(infos.GetValue("INNER.D.Z", 0.0)*unit_converter);
301 
302  // To get back to INDRA phi-coordinates, all points need to be rotated
303  // by -150 degrees around the Z-axis
304  for (int i = 0; i <= 3; i++) {
305  fInnerFront[i].RotateZ(-150.*TMath::DegToRad());
306  }
308 
309  fOuterFront[0].SetX(infos.GetValue("OUTER.A.X", 0.0)*unit_converter);
310  fOuterFront[0].SetY(infos.GetValue("OUTER.A.Y", 0.0)*unit_converter);
311  fOuterFront[0].SetZ(infos.GetValue("OUTER.A.Z", 0.0)*unit_converter);
312  fOuterFront[3].SetX(infos.GetValue("OUTER.B.X", 0.0)*unit_converter);
313  fOuterFront[3].SetY(infos.GetValue("OUTER.B.Y", 0.0)*unit_converter);
314  fOuterFront[3].SetZ(infos.GetValue("OUTER.B.Z", 0.0)*unit_converter);
315  fOuterFront[2].SetX(infos.GetValue("OUTER.C.X", 0.0)*unit_converter);
316  fOuterFront[2].SetY(infos.GetValue("OUTER.C.Y", 0.0)*unit_converter);
317  fOuterFront[2].SetZ(infos.GetValue("OUTER.C.Z", 0.0)*unit_converter);
318  fOuterFront[1].SetX(infos.GetValue("OUTER.D.X", 0.0)*unit_converter);
319  fOuterFront[1].SetY(infos.GetValue("OUTER.D.Y", 0.0)*unit_converter);
320  fOuterFront[1].SetZ(infos.GetValue("OUTER.D.Z", 0.0)*unit_converter);
321 
322  // To get back to INDRA phi-coordinates, all points need to be rotated
323  // by -150 degrees around the Z-axis
324  for (int i = 0; i <= 3; i++) {
325  fOuterFront[i].RotateZ(-150.*TMath::DegToRad());
326  }
328 
329  phi0 = infos.GetValue("PHIZERO", 30.0);
330  thetaMin = infos.GetValue("THETAMIN", 0.0);
331  thetaMax = infos.GetValue("THETAMAX", 0.0);
332  Ndets = infos.GetValue("NDETS", 1);
333  deltaPhi = 360. / Ndets;
334 
335  // calculate theoretical geometry:
336  // points of intersection with the plane defined by real Huguet geometry
337  // and the 4 vectors to theoretical thetamin/max phimin/max
340  Ph0 - deltaPhi / 2.,
341  Ph0 + deltaPhi / 2.,
342  fFrameFront);
343  // calculate centre of frame = direction of detector
345  fFrameMat.SetMaterial(infos.GetValue("FRAME.MATERIAL", "Al"));
346 
347  fInnerPads = infos.GetValue("INNER.PADS", 1);
348  fOuterPads = infos.GetValue("OUTER.PADS", 0);
349  fInnerRing = infos.GetValue("INNER.RING", ring);
350  fOuterRing = infos.GetValue("OUTER.RING", 0);
351  fInnerDmod = infos.GetValue("INNER.DMOD", 1);
352  fOuterDmod = infos.GetValue("OUTER.DMOD", 1);
353  fInnerModmin = infos.GetValue("INNER.MODMIN", 1);
354  fOuterModmin = infos.GetValue("OUTER.MODMIN", 1);
355  fModmax = infos.GetValue("MODMAX", 24);
356 
357  // read infos on internal structure of detector
358  auto nlay = infos.GetValue("LAYERS", 1);
359 
360  fActiveLayer = infos.GetValue("ACTIVELAYER", 1);
361  for (int lay = 1; lay <= nlay; ++lay) {
362  auto mat = new KVMaterial;
363  mat->SetMaterial(infos.GetValue(Form("LAYER.%d.MATERIAL", lay), ""));
364  auto gas_pressure = infos.GetValue(Form("LAYER.%d.PRESSURE", lay), -1.0);
365  if (gas_pressure > 0) mat->SetPressure(gas_pressure * KVUnits::torr); // gas pressure in Torr
366  auto thick = infos.GetValue(Form("LAYER.%d.THICK", lay), -1.0);
367  if (thick > 0) mat->SetThickness(thick * KVUnits::cm); // linear thickness in cm
368  auto dens = infos.GetValue(Form("LAYER.%d.DENSITY", lay), -1.0);
369  if (dens > 0) mat->SetAreaDensity(dens * KVUnits::ug / KVUnits::cm / KVUnits::cm); // area density in ug/cm2
370 
371  fCurrentDetector.AddAbsorber(mat);
372  }
373  if (fActiveLayer > 1) fCurrentDetector.SetActiveLayer(fActiveLayer - 1);
374 }
375 
376 
377 
378 
380 
382 {
383  printf("Detector name : %s\n", fDetName.Data());
384  printf("Total thickness : %f cm\n", fCurrentDetector.GetTotalThicknessInCM());
385  printf("Frame centre:\n");
387  printf("Inner centre:\n");
389  printf("Outer centre: \n");
391  printf("Coordinates of outer pads :\n");
392  for (int i = 0; i < 4; i++) fOuterFront[i].Print();
393  printf("Coordinates of inner pads :\n");
394  for (int i = 0; i < 4; i++) fInnerFront[i].Print();
395  printf("Material of outer frame : %s\n", fFrameMat.GetTitle());
396 }
397 
398 
399 
400 
404 
406 {
407  // Create the TGeoVolume corresponding to the outer casing
408  // (dead zone) of the detector
409 
410  TVector3 fFrameBack[4];
411  TVector3 fFrameBackCentre;
412  //CalculateBackPlaneCoordinates(fFrameFront, fFrameCentre, fTotalThickness, fFrameBack);
413  // make deadzone be 1um thick
414  Double_t dz = 5.e-5;
416  CalculateCentre(fFrameBack, fFrameBackCentre);
417 
418  TVector3 corners[8]; // 8 vertices of the volume
420  TransformToOwnFrame(fFrameBack, fFrameBackCentre, &corners[4]);
421 
422  Double_t vertices[16];
423  for (int i = 0; i < 8; i++) {
424  vertices[2 * i] = corners[i].X();
425  vertices[2 * i + 1] = corners[i].Y();
426  }
427 
428  //Double_t dz = 0.99 * fTotalThickness / 2.;
429  TString vol_name;
430  vol_name.Form("STRUCT_%s_%02d", det_type.Data(), ring_num);
433  vol_name.Form("DEADZONE_%s_%02d", det_type.Data(), ring_num);
435  Double_t offX, offY;
436  CorrectCoordinates(vertices, offX, offY);
437  // place the deadzone 1um (=1.e-4 cm) behind the detector entrance window
438  TGeoTranslation* offset = new TGeoTranslation(offX, offY, -(0.5 * fCurrentDetector.GetTotalThicknessInCM() - (1.e-4 + dz)));
439  TGeoVolume* frame = gGeoManager->MakeArb8(vol_name.Data(), med, dz, vertices);
440  frame->SetLineColor(med->GetMaterial()->GetDefaultColor());
441  fFrameVolume->AddNode(frame, 1, offset);
442 }
443 
444 
445 
446 
450 
452 {
453  // takes the four points (TVector3) in the array and transforms them
454  // to a reference frame in which the +ve z-axis goes through their centre
455 
456  TRotation rot_to_frame;
457  rot_to_frame.SetYEulerAngles(-centre.Phi(), -centre.Theta(), 0.);
458  TVector3 displZ(0, 0, centre.Mag());
459  for (int i = 0; i < 4; i++) {
460  ownframe[i] = rot_to_frame * orig[i] - displZ;
461  }
462 }
463 
464 
465 
475 
477 {
478  // Called by KVINDRA::set_detector_thicknesses().
479  //
480  // Is 'detname' is present in the current geometry, we override its nominal thickness
481  // (read from the indra-struct* file) with the given value and return kTRUE.
482  //
483  // If 'detname' is not present in the current geometry, we print a warning message and return
484  // kFALSE (incoherency between the indra-struct* present detectors
485  // & the list of detector thicknesses).
486 
487  auto det = detector_map.find(detname.Data());
488  if (det != detector_map.end()) {
489  det->second.thick = thickness;
490  return kTRUE;
491  }
492  Warning("SetDetectorThickness", "New thickness value %f given for %s,"
493  " but detector is apparently absent from geometry?",
494  thickness, detname.Data());
495  return kFALSE;
496 }
497 
498 
499 
500 
503 
505 {
506  // position frame (dead zone) volume in geometry
507 
509  TGeoRotation rot1, rot2;
510  rot2.SetAngles(phi + 90., theta, 0.);
511  rot1.SetAngles(-90., 0., 0.);
512  // distance to frame centre
513  Double_t trans_z = fFrameCentre.Mag() + fCurrentDetector.GetTotalThicknessInCM() / 2.;
514 
515  TGeoTranslation tran(0, 0, trans_z);
516  TGeoHMatrix h = rot2 * tran * rot1;
517  TGeoHMatrix* ph = new TGeoHMatrix(h);
518 
519  // add detector volume to geometry
520  gGeoManager->GetTopVolume()->AddNode(fFrameVolume, copy_no, ph);
521 }
522 
523 
524 
525 
528 
530 {
531  // position detector inside frame
532 
535 }
536 
537 
538 
540 
542 {
543 #ifdef DEBUG
544  Info("CheckDetectorPresent", "%s - present:%d thick:%f",
545  detname.Data(), detector_map[detname.Data()].present, detector_map[detname.Data()].thick);
546 #endif
547  auto it = detector_map.find(detname.Data());
548  return (it != detector_map.end()) && it->second.present;
549 }
550 
551 
552 
554 
555 void INDRAGeometryBuilder::MakeRing(const Char_t* det, int ring)
556 {
557 
558  fCurrentDetectorType = det;
559  fCurrentDetector.RemoveAllAbsorbers();
560 
561  if (!strcmp(det, "PHOS"))
562  fDetName.Form("%s_01", det);
563  else
564  fDetName.Form("%s_%02d01", det, ring);
565  ReadDetCAO(fDetName, ring);
566  //Print();
567  Double_t phi = phi0;
568  Int_t innerMod = fInnerModmin;
569  Int_t outerMod = fOuterModmin;
570  int i = 1;
571 
572  cout << fDetName.Data() << " " << fInnerCentre.Mag() << " " <<
573  0.5 * (fInnerFront[0].Theta() + fInnerFront[3].Theta())*TMath::RadToDeg() << " " <<
574  0.5 * (fInnerFront[1].Theta() + fInnerFront[2].Theta())*TMath::RadToDeg() << " " <<
575  0.5 * (fInnerFront[2].Phi() + fInnerFront[3].Phi())*TMath::RadToDeg() << " " <<
576  0.5 * (fInnerFront[0].Phi() + fInnerFront[1].Phi())*TMath::RadToDeg() << endl;
577 
578 // check presence of all detectors of ring
579  Int_t npresent = 0;
580  Int_t ntotal = 0;
581 
582  for (i = 1; i <= Ndets; i++) {
583  if (!strcmp(det, "PHOS")) fDetName.Form("%s_%02d", det, innerMod);
584  else fDetName.Form("%s_%02d%02d", det, fInnerRing, innerMod);
585  ntotal++;
586  npresent += (Int_t)CheckDetectorPresent(fDetName);
587 
588  innerMod += fInnerDmod;
589 
590  if (fInnerPads == 3) {
591  if (!strcmp(det, "PHOS")) fDetName.Form("%s_%02d", det, innerMod);
592  else fDetName.Form("%s_%02d%02d", det, fInnerRing, innerMod);
593  ntotal++;
594  npresent += (Int_t)CheckDetectorPresent(fDetName);
595  innerMod += fInnerDmod;
596  if (!strcmp(det, "PHOS")) fDetName.Form("%s_%02d", det, innerMod);
597  else fDetName.Form("%s_%02d%02d", det, fInnerRing, innerMod);
598  ntotal++;
599  npresent += (Int_t)CheckDetectorPresent(fDetName);
600  innerMod += fInnerDmod;
601  }
602  else {
603  if (fInnerPads == 2) {
604  if (!strcmp(det, "PHOS")) fDetName.Form("%s_%02d", det, innerMod);
605  else fDetName.Form("%s_%02d%02d", det, fInnerRing, innerMod);
606  ntotal++;
607  npresent += (Int_t)CheckDetectorPresent(fDetName);
608  innerMod += fInnerDmod;
609  }
610  if (fOuterPads) {
611  if (!strcmp(det, "PHOS")) fDetName.Form("%s_%02d", det, outerMod);
612  else fDetName.Form("%s_%02d%02d", det, fOuterRing, outerMod);
613  ntotal++;
614  npresent += (Int_t)CheckDetectorPresent(fDetName);
615  outerMod += fOuterDmod;
616  if (fOuterPads == 2) {
617  if (!strcmp(det, "PHOS")) fDetName.Form("%s_%02d", det, outerMod);
618  else fDetName.Form("%s_%02d%02d", det, fOuterRing, outerMod);
619  ntotal++;
620  npresent += (Int_t)CheckDetectorPresent(fDetName);
621  outerMod += fOuterDmod;
622  }
623  }
624  }
625  }
626  if (!npresent) {
627  Info("MakeRing", "Detector type %s ring number %d : ABSENT", det, ring);
628  return;
629  }
630  Info("MakeRing", "Detector type %s ring number %d : %d/%d detectors present", det, ring, npresent, ntotal);
631 
632  innerMod = fInnerModmin;
633  outerMod = fOuterModmin;
634 
635  bool made_prototype_block{false};
636 
637  for (i = 1; i <= Ndets; i++) {
638 
639  // check absence of whole block
640  ntotal = 0;
641  npresent = 0;
642  if (!strcmp(det, "PHOS")) fDetName.Form("%s_%02d", det, innerMod);
643  else fDetName.Form("%s_%02d%02d", det, fInnerRing, innerMod);
644  ntotal++;
645  auto first_is_present = CheckDetectorPresent(fDetName);
646  npresent += (Int_t)first_is_present;
647  // check if thickness/pressure of first detector in block has changed compared to current prototype
648  if (first_is_present) {
649  if (fCurrentDetector.IsGasDetector()) {
650 // if(detector_map[fDetName.Data()].thick != fCurrentDetector.GetPressure()) {
651 // // change pressure of gas
652 // fCurrentDetector.SetPressure(detector_map[fDetName.Data()].thick);
653 // made_prototype_block = false; // set flag to generate new prototype
654 // }
655  }
656  else {
657  if (detector_map[fDetName.Data()].thick != fCurrentDetector.GetThickness()) {
658  // change thickness of current active layer
659  fCurrentDetector.SetThickness(detector_map[fDetName.Data()].thick);
660  made_prototype_block = false; // set flag to generate new prototype
661  }
662  }
663  }
664 
665  innerMod += fInnerDmod;
666 
667  if (fInnerPads == 3) {
668  if (!strcmp(det, "PHOS")) fDetName.Form("%s_%02d", det, innerMod);
669  else fDetName.Form("%s_%02d%02d", det, fInnerRing, innerMod);
670  ntotal++;
671  npresent += (Int_t)CheckDetectorPresent(fDetName);
672  innerMod += fInnerDmod;
673  if (!strcmp(det, "PHOS")) fDetName.Form("%s_%02d", det, innerMod);
674  else fDetName.Form("%s_%02d%02d", det, fInnerRing, innerMod);
675  ntotal++;
676  npresent += (Int_t)CheckDetectorPresent(fDetName);
677  innerMod += fInnerDmod;
678  }
679  else {
680  if (fInnerPads == 2) {
681  if (!strcmp(det, "PHOS")) fDetName.Form("%s_%02d", det, innerMod);
682  else fDetName.Form("%s_%02d%02d", det, fInnerRing, innerMod);
683  ntotal++;
684  npresent += (Int_t)CheckDetectorPresent(fDetName);
685  innerMod += fInnerDmod;
686  }
687  if (fOuterPads) {
688  if (!strcmp(det, "PHOS")) fDetName.Form("%s_%02d", det, outerMod);
689  else fDetName.Form("%s_%02d%02d", det, fOuterRing, outerMod);
690  ntotal++;
691  npresent += (Int_t)CheckDetectorPresent(fDetName);
692  outerMod += fOuterDmod;
693  if (fOuterPads == 2) {
694  if (!strcmp(det, "PHOS")) fDetName.Form("%s_%02d", det, outerMod);
695  else fDetName.Form("%s_%02d%02d", det, fOuterRing, outerMod);
696  ntotal++;
697  npresent += (Int_t)CheckDetectorPresent(fDetName);
698  outerMod += fOuterDmod;
699  }
700  }
701  }
702  if (!npresent) Info("MakeRing", "\tBlock %d: ABSENT", i);
703  else if (npresent < ntotal) {
704  Info("MakeRing", "\tBlock %d: %d/%d detectors present", i, npresent, ntotal);
705  Info("MakeRing", "\tCASE NOT TREATED. ALL DETECTORS PRESENT.");
706  }
707  if (npresent) {
708 
709  if (!made_prototype_block) {
710  // Create prototype for ring
711  made_prototype_block = true;
712 
713  Info("MakeRing", "DET:%s RING:%d Making new prototype group for i=%d/%d",
714  det, ring, i, Ndets);
715 
716  /* build and add frame */
717  MakeFrame(det, ring);
718 
719  // make pads in inner ring
721  PlaceDetector();
722  if (fInnerPads == 3) {
724  PlaceDetector();
725  TVector3 reflex[4];
727  TVector3 refcent;
728  CalculateCentre(reflex, refcent);
729  MakeDetector("A3", reflex, refcent);
730  PlaceDetector();
731  }
732  else {
733  if (fInnerPads == 2) {
734  TVector3 reflex[4];
736  TVector3 refcent;
737  CalculateCentre(reflex, refcent);
738  MakeDetector("A2", reflex, refcent);
739  PlaceDetector();
740  }
741  if (fOuterPads) {
742  // make pads in outer ring
744  PlaceDetector();
745  if (fOuterPads == 2) {
746  TVector3 reflex[4];
748  TVector3 refcent;
749  CalculateCentre(reflex, refcent);
750  MakeDetector("B2", reflex, refcent);
751  PlaceDetector();
752  }
753  }
754  }
755  }
756 
757  PlaceFrame(phi, i);
758  }
759 
760  if (((ring > 9 && ring < 13) && i == 1) || (ring > 12 && i == 2)) {
761  fEtalonTheta[ring - 10] = fFrameCentre.Theta() * TMath::RadToDeg();
762  fEtalonPhi[ring - 10] = phi;
764  fEtalonPhi[ring - 9] = phi;
765  }
766  phi += deltaPhi;
767  }
768 
769 }
770 
771 
772 
773 
776 
778 {
779 
780  // make volume corresponding to the actual detector
781 
782  TVector3 corners[8]; // 8 vertices of the volume
783  Double_t vertices[16];
784 
785  // Check whether this is a real multi-layer detector
786  // i.e. make sure all "layers" have non-zero thickness
787  Bool_t multi_layer = fCurrentDetector.IsMultiLayer();
788  if (multi_layer) {
789  TIter next(fCurrentDetector.GetListOfAbsorbers());
790  KVMaterial* abs;
791  Int_t no_abs = 0;
792  while ((abs = (KVMaterial*)next())) {
793  Double_t thick = abs->GetThickness();
794  if (thick > 0.0) ++no_abs;
795  }
796  multi_layer = (no_abs > 1);
797  }
798  if (multi_layer) {
799  fDetVolume = gGeoManager->MakeVolumeAssembly(Form("DET_%s", det));
801  }
802  TVector3 frontPlane[4], backPlane[4], frontCentre, backCentre;
803  // front plane of first absorber is front plane of detector
804  for (int i = 0; i < 4; i++) frontPlane[i] = som[i];
805  frontCentre = cen;
806 
807  /**** BUILD & ADD LAYERS ****/
808  TIter next(fCurrentDetector.GetListOfAbsorbers());
809  KVMaterial* abs;
810  Double_t depth_in_det = 0.;
811  Int_t no_abs = 1;
812 
813  Double_t offX, offY; //offset of each layer
814  fDetectorPosition = 0;
815 
816  auto fTotalThickness = fCurrentDetector.GetTotalThicknessInCM();
817 
818  while ((abs = (KVMaterial*)next())) {
819  // get medium for absorber
820  TGeoMedium* med = abs->GetGeoMedium();
821  Double_t thick = abs->GetThickness();
822  if (thick == 0.0) {
823  no_abs++; // ignore zero thickness layers
824  continue;
825  }
826 
827  // calculate coordinates of back plane
828  CalculateBackPlaneCoordinates(frontPlane, frontCentre, thick, backPlane);
829  // calculate centre of back plane
830  CalculateCentre(backPlane, backCentre);
831  // calculate corners of volume
832  TransformToOwnFrame(frontPlane, fFrameCentre, corners);
833  TransformToOwnFrame(backPlane, fFrameCentre, &corners[4]);
834  for (int i = 0; i < 8; i++) {
835  vertices[2 * i] = corners[i].X();
836  vertices[2 * i + 1] = corners[i].Y();
837  }
838 
839  Double_t dz = thick / 2.;
840  TString vol_name;
841  if (multi_layer) {
842  if (no_abs == fActiveLayer) vol_name = Form("ACTIVE_%s", det);
843  else vol_name = Form("%s_%d_%s", det, no_abs, abs->GetName());
844  }
845  else
846  vol_name = Form("DET_%s", det);
847 
848  CorrectCoordinates(vertices, offX, offY);
849  TGeoVolume* vol =
850  gGeoManager->MakeArb8(vol_name.Data(), med, dz, vertices);
851  vol->SetLineColor(med->GetMaterial()->GetDefaultColor());
852  if (multi_layer) {
853  /*** position absorber in mother ***/
854  Double_t trans_z = -fTotalThickness / 2. + depth_in_det + dz; // (note: reference is CENTRE of absorber)
855  TGeoTranslation* tr = new TGeoTranslation(offX, offY, trans_z);
856  fDetVolume->AddNode(vol, no_abs, tr);
857  }
858  else {
859  // single absorber: mother is absorber is detector is mother is ...
860  fDetVolume = vol;
861  fDetectorPosition = new TGeoTranslation(offX, offY, 0);
862  }
863 
864  depth_in_det += thick;
865  no_abs++;
866 
867  // front of next absorber is back of current absorber
868  for (int i = 0; i < 4; i++) frontPlane[i] = backPlane[i];
869  frontCentre = backCentre;
870  }
871 }
872 
873 
874 
883 
885 {
886  // TVector3 corners[4] array of corner coordinates in usual order:
887  // corners[3] : theta-min, phi-min
888  // corners[2] : theta-max, phi-min
889  // corners[1] : theta-max, phi-max
890  // corners[0] : theta-min, phi-max
891  //
892  // Calculate the intersection of the normal to the plane passing through the origin.
893 
894  TVector3 a10 = corners[1] - corners[0];
895  TVector3 a21 = corners[2] - corners[1];
896  TVector3 normal = a10.Cross(a21);
897  Double_t d = (corners[3] * normal) / normal.Mag2();
898  inter = normal * d;
899 }
900 
901 
902 
903 
912 
914  Double_t thetamax, Double_t phimin, Double_t phimax, TVector3* corners)
915 {
916  // fill TVector3 corners[4] array in usual order:
917  // corners[3] : theta-min, phi-min
918  // corners[2] : theta-max, phi-min
919  // corners[1] : theta-max, phi-max
920  // corners[0] : theta-min, phi-max
921  // theta, phi in degrees
922  // These points lie in the plane defined by the equivalent TVEctor3 plane[4] corners
923 
924  TVector3 a10 = plane[1] - plane[0];
925  TVector3 a21 = plane[2] - plane[1];
926  TVector3 normal = a10.Cross(a21);
927  Double_t d0 = plane[3] * normal;
928 
929  TVector3 l;
930  l.SetMagThetaPhi(1., thetamin * TMath::DegToRad(), phimin * TMath::DegToRad());
931  corners[3] = l * (d0 / (l * normal));
932  l.SetMagThetaPhi(1., thetamax * TMath::DegToRad(), phimin * TMath::DegToRad());
933  corners[2] = l * (d0 / (l * normal));
934  l.SetMagThetaPhi(1., thetamax * TMath::DegToRad(), phimax * TMath::DegToRad());
935  corners[1] = l * (d0 / (l * normal));
936  l.SetMagThetaPhi(1., thetamin * TMath::DegToRad(), phimax * TMath::DegToRad());
937  corners[0] = l * (d0 / (l * normal));
938 }
939 
940 
941 
943 
944 std::vector<INDRAGeometryBuilder::theta_phi> INDRAGeometryBuilder::GetDirectionsToTestForImport() const
945 {
946  std::vector<std::vector<theta_phi>> CSI_COORDS = {
947  // Ring 1
948  { {2.40628, 30}, {2.40628, 60}, {2.40628, 90}, {2.40628, 120}, {2.40628, 150}, {2.40628, 180}, {2.40628, 210}, {2.40628, 240},
949  {2.40628, 270}, {2.40628, 300}, {2.40628, 330}, {2.40628, 0}
950  },
951  // Ring 2
952  { {3.59843, 30}, {3.59843, 60}, {3.59843, 90}, {3.59843, 120},
953  {3.59843, 150}, {3.59843, 180}, {3.59843, 210}, {3.59843, 240}, {3.59843, 270}, {3.59843, 300}, {3.59843, 330}, {3.59843, 0}
954  },
955  // Ring 3
956  { {5.6605, 20.427}, {5.6605, 39.573}, {5.6605, 50.427}, {5.6605, 69.573}, {5.6605, 80.427}, {5.6605, 99.573}, {5.6605, 110.427},
957  {5.6605, 129.573}, {5.6605, 140.427}, {5.6605, 159.573}, {5.6605, 170.427}, {5.6605, 189.573}, {5.6605, 200.427}, {5.6605, 219.573},
958  {5.6605, 230.427}, {5.6605, 249.573}, {5.6605, 260.427}, {5.6605, 279.573}, {5.6605, 290.427}, {5.6605, 309.573}, {5.6605, 320.427},
959  {5.6605, 339.573}, {5.6605, 350.427}, {5.6605, 9.57299}
960  },
961  // Ring 4
962  { {8.23882, 20.2681}, {8.23882, 39.7319}, {8.23882, 50.2681}, {8.23882, 69.7319},
963  {8.23882, 80.2681}, {8.23882, 99.7319}, {8.23882, 110.268}, {8.23882, 129.732}, {8.23882, 140.268}, {8.23882, 159.732},
964  {8.23882, 170.268}, {8.23882, 189.732}, {8.23882, 200.268}, {8.23882, 219.732}, {8.23882, 230.268}, {8.23882, 249.732},
965  {8.23882, 260.268}, {8.23882, 279.732}, {8.23882, 290.268}, {8.23882, 309.732}, {8.23882, 320.268}, {8.23882, 339.732},
966  {8.23882, 350.268}, {8.23882, 9.73186}
967  },
968  // Ring 5
969  { {11.7348, 20.452}, {11.7348, 39.548}, {11.7348, 50.452}, {11.7348, 69.548}, {11.7348, 80.452},
970  {11.7348, 99.548}, {11.7348, 110.452}, {11.7348, 129.548}, {11.7348, 140.452}, {11.7348, 159.548}, {11.7348, 170.452},
971  {11.7348, 189.548}, {11.7348, 200.452}, {11.7348, 219.548}, {11.7348, 230.452}, {11.7348, 249.548}, {11.7348, 260.452},
972  {11.7348, 279.548}, {11.7348, 290.452}, {11.7348, 309.548}, {11.7348, 320.452}, {11.7348, 339.548}, {11.7348, 350.452},
973  {11.7348, 9.54796}
974  },
975  // Ring 6
976  { {16.4298, 20.1517}, {16.4298, 39.8483}, {16.4298, 50.1517}, {16.4298, 69.8483}, {16.4298, 80.1517},
977  {16.4298, 99.8483}, {16.4298, 110.152}, {16.4298, 129.848}, {16.4298, 140.152}, {16.4298, 159.848}, {16.4298, 170.152},
978  {16.4298, 189.848}, {16.4298, 200.152}, {16.4298, 219.848}, {16.4298, 230.152}, {16.4298, 249.848}, {16.4298, 260.152},
979  {16.4298, 279.848}, {16.4298, 290.152}, {16.4298, 309.848}, {16.4298, 320.152}, {16.4298, 339.848}, {16.4298, 350.152},
980  {16.4298, 9.84832}
981  },
982  // Ring 7
983  { {23.1125, 20.5305}, {23.1125, 39.4695}, {23.1125, 50.5305}, {23.1125, 69.4695}, {23.1125, 80.5305},
984  {23.1125, 99.4695}, {23.1125, 110.531}, {23.1125, 129.469}, {23.1125, 140.531}, {23.1125, 159.469}, {23.1125, 170.531},
985  {23.1125, 189.469}, {23.1125, 200.531}, {23.1125, 219.469}, {23.1125, 230.531}, {23.1125, 249.469}, {23.1125, 260.531},
986  {23.1125, 279.469}, {23.1125, 290.531}, {23.1125, 309.469}, {23.1125, 320.531}, {23.1125, 339.469}, {23.1125, 350.531},
987  {23.1125, 9.46947}
988  },
989  // Ring 8
990  { {30.1022, 20.2707}, {30.1022, 39.7293}, {30.1022, 50.2707}, {30.1022, 69.7293}, {30.1022, 80.2707},
991  {30.1022, 99.7293}, {30.1022, 110.271}, {30.1022, 129.729}, {30.1022, 140.271}, {30.1022, 159.729}, {30.1022, 170.271},
992  {30.1022, 189.729}, {30.1022, 200.271}, {30.1022, 219.729}, {30.1022, 230.271}, {30.1022, 249.729}, {30.1022, 260.271},
993  {30.1022, 279.729}, {30.1022, 290.271}, {30.1022, 309.729}, {30.1022, 320.271}, {30.1022, 339.729}, {30.1022, 350.271},
994  {30.1022, 9.72928}
995  },
996  // Ring 9
997  { {39.6964, 20.3843}, {39.6964, 39.6157}, {39.6964, 50.3843}, {39.6964, 69.6157}, {39.6964, 80.3843},
998  {39.6964, 99.6157}, {39.6964, 110.384}, {39.6964, 129.616}, {39.6964, 140.384}, {39.6964, 159.616}, {39.6964, 170.384},
999  {39.6964, 189.616}, {39.6964, 200.384}, {39.6964, 219.616}, {39.6964, 230.384}, {39.6964, 249.616}, {39.6964, 260.384},
1000  {39.6964, 279.616}, {39.6964, 290.384}, {39.6964, 309.616}, {39.6964, 320.384}, {39.6964, 339.616}, {39.6964, 350.384},
1001  {39.6964, 9.61571}
1002  },
1003  // Ring 10
1004  { {49.4614, 20.6178}, {46., 39.3822}, // trajectory missing etalon
1005  {49.4614, 50.6178}, {49.4614, 69.3822}, {49.4614, 80.6178},
1006  {49.4614, 99.3822}, {49.4614, 110.618}, {49.4614, 129.382}, {49.4614, 140.618}, {49.4614, 159.382}, {49.4614, 170.618},
1007  {49.4614, 189.382}, {49.4614, 200.618}, {49.4614, 219.382}, {49.4614, 230.618}, {49.4614, 249.382}, {49.4614, 260.618},
1008  {49.4614, 279.382}, {49.4614, 290.618}, {49.4614, 309.382}, {49.4614, 320.618}, {49.4614, 339.382}, {49.4614, 350.618},
1009  {49.4614, 9.38224}
1010  },
1011  // Ring 11
1012  { {63.6629, 20.7968}, {60., 39.2032}, // trajectory missing etalon
1013  {63.6629, 50.7968}, {63.6629, 69.2032}, {63.6629, 80.7968},
1014  {63.6629, 99.2032}, {63.6629, 110.797}, {63.6629, 129.203}, {63.6629, 140.797}, {63.6629, 159.203}, {63.6629, 170.797},
1015  {63.6629, 189.203}, {63.6629, 200.797}, {63.6629, 219.203}, {63.6629, 230.797}, {63.6629, 249.203}, {63.6629, 260.797},
1016  {63.6629, 279.203}, {63.6629, 290.797}, {63.6629, 309.203}, {63.6629, 320.797}, {63.6629, 339.203}, {63.6629, 350.797},
1017  {63.6629, 9.20323}
1018  },
1019  // Ring 12
1020  { {79.188, 21.4427}, {75., 38.5573}, // trajectory missing etalon
1021  {79.188, 51.4427}, {79.188, 68.5573}, {79.188, 81.4427}, {79.188, 98.5573},
1022  {79.188, 111.443}, {79.188, 128.557}, {79.188, 141.443}, {79.188, 158.557}, {79.188, 171.443}, {79.188, 188.557}, {79.188, 201.443},
1023  {79.188, 218.557}, {79.188, 231.443}, {79.188, 248.557}, {79.188, 261.443}, {79.188, 278.557}, {79.188, 291.443}, {79.188, 308.557},
1024  {79.188, 321.443}, {79.188, 338.557}, {79.188, 351.443}, {79.188, 8.55734}
1025  },
1026  // Ring 13
1027  { {101.234, 28.5099}, {101.703, 45}, {101.234, 61.4901}, {95., 73.5099}, // trajectory missing etalon
1028  {101.703, 90}, {101.234, 106.49}, {101.234, 118.51}, {101.703, 135}, {101.234, 151.49}, {101.234, 163.51},
1029  {101.703, 180}, {101.234, 196.49}, {101.234, 208.51}, {101.703, 225}, {101.234, 241.49}, {101.234, 253.51}, {101.703, 270},
1030  {101.234, 286.49}, {101.234, 298.51}, {101.703, 315}, {101.234, 331.49}, {101.234, 343.51}, {101.703, 0}, {101.234, 16.4901}
1031  },
1032  // Ring 14
1033  { {118.722, 30.9923}, {118.722, 59.0077}, {118.722, 75.9923}, // trajectory missing etalon
1034  {118.722, 104.008}, {118.722, 120.992}, {118.722, 149.008},
1035  {118.722, 165.992}, {118.722, 194.008}, {118.722, 210.992}, {118.722, 239.008}, {118.722, 255.992}, {118.722, 284.008},
1036  {118.722, 300.992}, {118.722, 329.008}, {118.722, 345.992}, {118.722, 14.0077}
1037  },
1038  // Ring 15
1039  { {136.289, 30.5072}, {136.289, 59.4928}, {136.289, 75.5072}, // trajectory missing etalon
1040  {136.289, 104.493}, {136.289, 120.507}, {136.289, 149.493}, {136.289, 165.507}, {136.289, 194.493},
1041  {136.289, 210.507}, {136.289, 239.493}, {136.289, 255.507}, {136.289, 284.493}, {136.289, 300.507}, {136.289, 329.493},
1042  {136.289, 345.507}, {136.289, 14.4928}
1043  },
1044  // Ring 16
1045  { {150.75, 45}, {150.75, 80}, // trajectory missing etalon
1046  {150.75, 135}, {150.75, 180}, {150.75, 225}, {150.75, 270}, {150.75, 315}, {150.75, 0}
1047  },
1048  // Ring 17
1049  { {168.561, 45}, {174., 90}, // trajectory missing etalon
1050  {168.561, 135}, {168.561, 180}, {168.561, 225}, {168.561, 270}, {168.561, 315}, {168.561, 0.}
1051  }
1052  };
1053  std::vector<theta_phi> ETALON_COORDS = {
1054  {50.389351, 36.335958}, // ring 10
1055  {63.6629, 39.2032}, // ring 11
1056  {79.188, 38.5573}, // ring 12
1057  {101.234, 73.5099}, // ring 13
1058  {117.825, 83.5543}, // ring 14
1059  {133.642, 82.1937}, // ring 15
1060  {149.375, 90}, // ring 16
1061  {164.703, 90} // ring 17
1062  };
1063  // small utility functions to access arrays, taking into account the fact that ring 2
1064  // modules are numbered 1, 3, 5, ...
1065  auto get_direction = [&](int ring, int module) {
1066  if (ring == 2) return CSI_COORDS[1][module / 2];
1067  return CSI_COORDS[ring - 1][module - 1];
1068  };
1069  auto get_etalon_direction = [&](int ring) {
1070  return ETALON_COORDS[ring - 10];
1071  };
1072  // now scan map of present detectors and add corresponding directions to vector for KVGeoImport
1073  std::vector<theta_phi> directions_for_import;
1074 
1075  using ring_t = std::unordered_map<int, int>;
1076  std::unordered_map<int, ring_t> ring_module;
1077  for (auto& p : detector_map) {
1078  if (p.second.module > 0) { //avoid etalon telescopes with module=0
1079  auto ring = p.second.ring;
1080  auto module = p.second.module;
1081  if (!ring_module[ring][module]) { // only add one direction for each ring/module pair
1082  directions_for_import.push_back(get_direction(ring, module));
1083  ++ring_module[ring][module];
1084  }
1085  }
1086  else { // etalon telescopes
1087  auto ring = p.second.ring;
1088  directions_for_import.push_back(get_etalon_direction(ring));
1089  }
1090  }
1091  return directions_for_import;
1092 }
1093 
1094 
1095 
1102 
1104 {
1105  // Make sure that all detectors in detector map are in the list of detectors
1106  // imported into the multidet array
1107  //
1108  // We also set the (simplified geometry) thetamin/max & phimin/max for each detector.
1109  // This is used e.g. in the GUI for visualising scalers during experiments.
1110 
1111  Info("CheckImportResults", "Checking results of import of %lu expected detectors",
1112  detector_map.size());
1113  bool ok = true;
1114  unsigned long found = 0;
1115  for (auto& det : detector_map) {
1116  auto _det = detlist->FindObject(det.first.c_str());
1117  if (!_det) {
1118  Error("CheckImportResults", "Detector %s was not imported",
1119  det.first.c_str());
1120  ok = false;
1121  }
1122  else {
1123  ++found;
1124  dynamic_cast<KVDetector*>(_det)->SetPhiMinMax(det.second.phiminmax.first,det.second.phiminmax.second);
1125  dynamic_cast<KVDetector*>(_det)->SetPolarMinMax(det.second.thetaminmax.first,det.second.thetaminmax.second);
1126  }
1127  }
1128  if (found < detector_map.size())
1129  Warning("CheckImportResults", "Found %lu imported detectors (%lu missing)",
1130  found, detector_map.size() - found);
1131  else
1132  Info("CheckImportResults", "All %lu expected detectors were imported", found);
1133  return ok;
1134 }
1135 
1136 
1137 
1139 
1141 {
1143  //gGeoManager->GetTopVolume()->SetVisContainers();
1145  gGeoManager->GetTopVolume()->Draw("ogl");
1146 }
1147 
1148 
1149 
1151 
1153 {
1154  for (int i = 0; i < 4; i++) {
1155  newpad[3 - i].SetMagThetaPhi(orig[i].Mag(), orig[i].Theta(), 2.*phicentre - orig[i].Phi());
1156  }
1157 }
1158 
1159 
1160 
1164 
1166 {
1167  //TO DO: multi-layer targets + target with angle to beam
1168 
1169  // target holder
1170  KVMaterial target_holder_mat("Al");
1171  new TGeoBBox("TARGET_FRAME", 3., 3., 0.1 / 2.);
1172  new TGeoEltu("TARGET_HOLE", 2., 2., 0.1 / 2.);
1173  TGeoCompositeShape* cs = new TGeoCompositeShape("TARGET_FRAME", "TARGET_FRAME - TARGET_HOLE");
1174  TGeoVolume* target_frame = new TGeoVolume("TARGET_FRAME", cs, target_holder_mat.GetGeoMedium());
1175  gGeoManager->GetTopVolume()->AddNode(target_frame, 1);
1176 
1177  // add target
1178  // only single-layer target treated correctly
1179  KVTarget* T = gIndra->GetTarget();
1180  if (T) {
1181  KVMaterial* targMat = (KVMaterial*)T->GetLayers()->First();
1182  TGeoVolume* target = gGeoManager->MakeEltu("TARGET", targMat->GetGeoMedium(), 2., 2., targMat->GetThickness() / 2.);
1184  }
1185 }
1186 
1187 
1188 
1190 
1191 void INDRAGeometryBuilder::Build(Bool_t withTarget, Bool_t closeGeometry)
1192 {
1193  if (!gGeoManager) {
1194  Error("Build", "You must define gGeoManager with KVMultiDetArray::CreateGeoManager before calling this method");
1195  return;
1196  }
1197 
1198  // read infos on present/absent detectors & nominal thicknesses/pressures
1200 
1201  // read specific dataset detector thicknesses
1202  gIndra->SetDetectorThicknesses();
1203 
1204  if (fWithPhoswich) MakeRing("PHOS", 1);
1205  else {
1206  MakeRing("SI", 1);
1207  MakeRing("CSI", 1);
1208  }
1209  for (int ring = 2; ring <= 16; ring += 2) {
1210  MakeRing("CI", ring);
1211  if (ring > 1 && ring < 10)MakeRing("SI", ring);
1212  MakeRing("CSI", ring);
1213  if (ring == 12) {
1214  MakeRing("CI", ring + 1);
1215  MakeRing("CSI", ring + 1);
1216  }
1217  }
1218  for (int ring = 10; ring <= 17; ring++) {
1219  if (CheckDetectorPresent(Form("SI75_%d", ring))) MakeEtalon(ring);
1220  }
1221  if (withTarget) BuildTarget();
1222  if (closeGeometry) {
1225  }
1226 
1227 }
1228 
1229 
1249 
1250 void INDRAGeometryBuilder::Build(const KVNumberList& rings, const KVNameValueList& detectors)
1251 {
1252  // Build geometry, using only the ring numbers in the KVNumberList, and
1253  // only the detectors which are in the KVNameValueList:
1254  //
1255  // KVNameValueList dets;
1256  // dets.SetValue("CI",1);
1257  // dets.SetValue("SI",1);
1258  // igb.Build("2-9", dets); // use INDRAGeometryBuilder object 'igb' to build
1259  // // ChIo and Silicon detectors of rings 2-9
1260  //
1261  // Possible detector types are "CI", "SI", "CSI", "PHOS"
1262  // If you want to see the target in the previous example, use dets.SetValue("TARGET",1)
1263  //
1264  // Include "ring+100" in number list to build etalon telescope for "ring"
1265  //
1266  // This method will not destroy any pre-existing geometry (gGeoManager),
1267  // but will create one if none exists.
1268  // Also it will not close the geometry, leaving the possibility to add ancillary
1269  // detectors.
1270 
1271  if (!gIndra) {
1272  Error("Build", "You must build the geometry with gDataSet->BuildMultiDetector() before calling this method");
1273  return;
1274  }
1275 
1276  if (!gGeoManager) {
1277  Error("Build", "You must defined gGeoManager with KVMultiDetArray::CreateGeoManager before calling this method");
1278  return;
1279  }
1280 
1281  if (rings.Contains(1)) {
1282  if (detectors.HasParameter("PHOS")) MakeRing("PHOS", 1);
1283  if (detectors.HasParameter("SI"))MakeRing("SI", 1);
1284  if (detectors.HasParameter("CSI"))MakeRing("CSI", 1);
1285  }
1286  for (int ring = 2; ring <= 16; ring += 2) {
1287  if (rings.Contains(ring) && detectors.HasParameter("CI")) MakeRing("CI", ring);
1288  if (ring > 1 && ring < 10) {
1289  if (rings.Contains(ring) && detectors.HasParameter("SI"))MakeRing("SI", ring);
1290  }
1291  if (rings.Contains(ring) && detectors.HasParameter("CSI"))MakeRing("CSI", ring);
1292  if (ring == 12) {
1293  if (rings.Contains(ring + 1) && detectors.HasParameter("CI"))MakeRing("CI", ring + 1);
1294  if (rings.Contains(ring + 1) && detectors.HasParameter("CSI"))MakeRing("CSI", ring + 1);
1295  }
1296  }
1297  for (int ring = 10; ring <= 17; ring++) {
1298  if (rings.Contains(ring + 100)) MakeEtalon(ring);
1299  }
1300 
1301  if (detectors.HasParameter("TARGET"))
1302  BuildTarget();
1303 }
1304 
1305 
1306 
1308 
1310 {
1311  KVMaterial mat_si("Si");
1312  KVMaterial mat_li("Li");
1313  KVMaterial mat_al("Al");
1314  TGeoMedium* Silicon = mat_si.GetGeoMedium();
1315  TGeoMedium* Lithium = mat_li.GetGeoMedium();
1316  TGeoMedium* Alu = mat_al.GetGeoMedium();
1317 
1318  Double_t sili_diameter_total = 2.54;
1319  Double_t holder_thickness = 0.05;
1320  Double_t holder_length = 1.0;
1321  Double_t sili_diameter_active = 2.36;
1322  Double_t sili_silicon_thickness = 0.22;
1323  Double_t sili_lithium_thickness = 0.0044;
1324  Double_t si75_thickness = 0.008;
1325  Double_t si75_diameter_active = 2.2;
1326 
1327  fEtalonVol = new TGeoVolumeAssembly("STRUCT_ETALON");
1329 
1330  TGeoVolume* holder = gGeoManager->MakeTube("DEADZONE_ETALON_HOLDER", Alu,
1331  (sili_diameter_total) / 2., (sili_diameter_total + 2 * holder_thickness) / 2., holder_length / 2.);
1332  holder->SetLineColor(holder->GetMaterial()->GetDefaultColor());
1333  fEtalonVol->AddNode(holder, 1);
1334 
1335  Double_t w = sili_silicon_thickness + sili_lithium_thickness;
1336  TGeoVolume* sili_dz = gGeoManager->MakeTube("DEADZONE_SILI", Alu,
1337  sili_diameter_active / 2., (sili_diameter_total) / 2., w / 2.);
1338  sili_dz->SetLineColor(sili_dz->GetMaterial()->GetDefaultColor());
1339 
1340  fEtalonVol->AddNode(sili_dz, 1, new TGeoTranslation(0, 0, holder_length / 4.));
1341 
1342  TGeoVolumeAssembly* sili = new TGeoVolumeAssembly("DET_SILI");
1343  sili->SetMedium(gGeoManager->GetMedium("Vacuum"));
1344  TGeoVolume* sili_si = gGeoManager->MakeTube("ACTIVE_SILI", Silicon,
1345  0., (sili_diameter_active) / 2., (sili_silicon_thickness) / 2.);
1346  TGeoVolume* sili_li = gGeoManager->MakeTube("SILI_LI", Lithium,
1347  0., (sili_diameter_active) / 2., (sili_lithium_thickness) / 2.);
1348  sili_si->SetLineColor(sili_si->GetMaterial()->GetDefaultColor());
1349  sili_li->SetLineColor(sili_li->GetMaterial()->GetDefaultColor());
1350  sili->AddNode(sili_si, 1, new TGeoTranslation(0, 0, -(w / 2. - sili_silicon_thickness / 2.)));
1351  sili->AddNode(sili_li, 1, new TGeoTranslation(0, 0, w / 2. - sili_lithium_thickness / 2.));
1352  fEtalonVol->AddNode(sili, 1, new TGeoTranslation(0, 0, holder_length / 4.));
1353 
1354  TGeoVolume* si75 = gGeoManager->MakeTube("DET_SI75", Silicon,
1355  0., (si75_diameter_active) / 2., (si75_thickness) / 2.);
1356  TGeoVolume* si75_dz = gGeoManager->MakeTube("DEADZONE_SI75", Alu,
1357  (si75_diameter_active) / 2., (sili_diameter_total) / 2., (si75_thickness) / 2.);
1358 
1359  fEtalonVol->AddNode(si75_dz, 1);
1360  fEtalonVol->AddNode(si75, 1);
1361 
1362 }
1363 
1364 
1365 
1370 
1372 {
1373  // Build and add etalon telescope for ring
1374  //Double_t theta[] = {51.075000,63.340000,79.435000,100.685000,118.235000,133.905000,149.790000,166.435000};
1375  //Double_t phi[] = {37.500000,37.500000,37.500000,90.000000,78.750000,78.750000,90.000000,90.000000};
1376  Double_t dist[] = {17.4005, 17.4005, 17.4005, 16.7005, 16.7005, 16.7005, 17.4005, 17.4005,};
1377 
1379 
1380  cout << "Etalons " << RING << " : " << fEtalonTheta[RING - 10] << " " << fEtalonPhi[RING - 10] << endl;
1381  TGeoTranslation trans;
1382  trans.SetDz(dist[RING - 10]);
1383  TGeoRotation rot1, rot2;
1384  TGeoHMatrix h;
1385  TGeoHMatrix* ph = 0;
1386 
1387 // rot2.SetAngles(phi[RING-10]+90., theta[RING-10], 0.);
1388 // rot1.SetAngles(-1.*phi[RING-10], 0., 0.);
1389  rot2.SetAngles(fEtalonPhi[RING - 10] + 90., fEtalonTheta[RING - 10], 0.);
1390  rot1.SetAngles(-1.*fEtalonPhi[RING - 10], 0., 0.);
1391 // if(RING==13){
1392 // TGeoTranslation p(4.5,0,0);
1393 // h = p * rot2 * trans * rot1;
1394 // }
1395  if (RING == 10) {
1396  TGeoTranslation p(1.5, 2.5, 0);
1397  h = rot2 * trans * p * rot1;
1398  }
1399  else if (RING == 11) {
1400  TGeoTranslation p(1.5, -1.5, 0);
1401  h = rot2 * trans * p * rot1;
1402  }
1403  else if (RING == 12) {
1404  TGeoTranslation p(1.5, 0, 0);
1405  h = rot2 * trans * p * rot1;
1406  }
1407  else if (RING == 13) {
1408  TGeoTranslation p(-4, -0.5, 0);
1409  h = rot2 * trans * p * rot1;
1410  }
1411  else if (RING == 14) {
1412  TGeoTranslation p(-1.7, 1.75, 0);
1413  h = rot2 * trans * p * rot1;
1414  }
1415  else if (RING == 15) {
1416  TGeoTranslation p(-1.7, -3, 0);
1417  h = rot2 * trans * p * rot1;
1418  }
1419  else if (RING == 16) {
1420  TGeoTranslation p(0, 2.5, 0);
1421  h = rot2 * trans * p * rot1;
1422  }
1423  else {
1424  TGeoTranslation p(0, -2.25, 0);
1425  h = rot2 * trans * p * rot1;
1426  }
1427  ph = new TGeoHMatrix(h);
1428  gGeoManager->GetTopVolume()->AddNode(fEtalonVol, RING, ph);
1429 }
1430 
1431 
int Int_t
unsigned int UInt_t
#define d(i)
bool Bool_t
char Char_t
constexpr Bool_t kFALSE
double Double_t
constexpr Bool_t kTRUE
const char Option_t
kEnvChange
kEnvAll
winID w
winID h TVirtualViewer3D TVirtualGLPainter p
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h offset
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t target
char name[80]
R__EXTERN TGeoManager * gGeoManager
char * Form(const char *fmt,...)
Build INDRA geometry from Huguet CAO infos.
void CorrectCoordinates(Double_t *, Double_t &, Double_t &)
void MakeDetector(const Char_t *det, TVector3 *som, TVector3 cen)
make volume corresponding to the actual detector
std::vector< theta_phi > GetDirectionsToTestForImport() const
void Print(Option_t *="") const override
Int_t Ndets
number of detectors in ring
Bool_t CheckImportResults(const KVSeqCollection *)
void CalculateBackPlaneCoordinates(TVector3 *frontcoords, TVector3 centre, Double_t depth, TVector3 *backcoords)
TGeoVolume * fDetVolume
geo volume representing frame
void CalculateCentre(TVector3 *corners, TVector3 &centre)
void read_indra_struct_file()
file containing structure of array
void ReadDetCAO(const Char_t *detname, Int_t ring)
std::unordered_map< std::string, detector_properties > detector_map
Int_t fActiveLayer
type name of current detector
void read_layer_infos(const Char_t *name)
read infos on layer 'name' in file "$KVROOT/KVFiles/data/indra-struct.[dataset].env"
TString fDetName
name of detector
TVector3 fInnerCentre
centre of inner face
void PlaceFrame(Double_t phi, Int_t copy_no)
position frame (dead zone) volume in geometry
KVMaterial fFrameMat
material of outer frame
void ReflectPad(TVector3 *orig, Double_t phicentre, TVector3 *newpad)
Double_t phi0
theoretical geometry
TVector3 fInnerFront[4]
coords of inner front face
Bool_t SetDetectorThickness(const TString &detname, Double_t thickness)
std::vector< detector_properties > read_telescope_infos(const Char_t *prefix, Int_t ring, Int_t mod, Int_t ntel, double thmin, double thmax, double phi)
read telescope infos in file "$KVROOT/KVFiles/data/indra-struct.[dataset].env"
void CalculateCornersInPlane(TVector3 *plane, Double_t thetamin, Double_t thetamax, Double_t phimin, Double_t phimax, TVector3 *corners)
TString fCurrentDetectorType
list of materials making up layers of current detector
TVector3 fOuterFront[4]
coords of outer front face
TVector3 fOuterCentre
centre of outer face
Bool_t CheckDetectorPresent(TString detname)
void TransformToOwnFrame(TVector3 *orig, TVector3 &centre, TVector3 *ownframe)
TVector3 fFrameFront[4]
coords of outer front face
INDRAGeometryBuilder(const TString &_data_set, Int_t current_run=-1)
Default constructor.
void Build(Bool_t withTarget=kTRUE, Bool_t closeGeometry=kTRUE)
void read_ring_infos(Int_t number, const Char_t *prefix)
read infos on ring in file "$KVROOT/KVFiles/data/indra-struct.[dataset].env"
void MakeRing(const Char_t *det, int ring)
void MakeFrame(TString det_type, Int_t ring_num)
TVector3 fFrameCentre
centre of frame
TGeoVolume * fFrameVolume
geo volume representing frame
void PlaceDetector()
position detector inside frame
TGeoTranslation * fDetectorPosition
TGeoVolumeAssembly * fEtalonVol
static Bool_t SearchKVFile(const Char_t *name, TString &fullpath, const Char_t *kvsubdir="")
Definition: KVBase.cpp:517
TString GetFullPathToDataSetFile(const Char_t *filename)
Definition: KVDataSet.cpp:1926
Description of physical materials used to construct detectors & targets; interface to range tables.
Definition: KVMaterial.h:89
virtual Double_t GetThickness() const
Definition: KVMaterial.cpp:484
virtual TGeoMedium * GetGeoMedium(const Char_t *="")
virtual void SetMaterial(const Char_t *type)
Definition: KVMaterial.cpp:217
KVTarget * GetTarget()
Handles lists of named parameters with different types, a list of KVNamedParameter objects.
Bool_t HasParameter(const Char_t *name) const
Strings used to represent a set of ranges of values.
Definition: KVNumberList.h:85
Bool_t Contains(Int_t val) const
returns kTRUE if the value 'val' is contained in the ranges defined by the number list
Bool_t End(void) const
Definition: KVNumberList.h:199
void Begin(void) const
Int_t Next(void) const
KaliVeda extensions to ROOT collection classes.
TObject * FindObject(const char *name) const override
Extension of ROOT TString class which allows backwards compatibility with ROOT v3....
Definition: KVString.h:73
void Begin(TString delim) const
Definition: KVString.cpp:565
Bool_t End() const
Definition: KVString.cpp:634
KVString Next(Bool_t strip_whitespace=kFALSE) const
Definition: KVString.cpp:695
Calculation/correction of energy losses of particles through an experimental target.
Definition: KVTarget.h:128
virtual const char * GetValue(const char *name, const char *dflt) const
virtual Int_t ReadFile(const char *fname, EEnvLevel level)
TGeoVolume * MakeTube(const char *name, TGeoMedium *medium, Double_t rmin, Double_t rmax, Double_t dz)
TGeoVolume * MakeArb8(const char *name, TGeoMedium *medium, Double_t dz, Double_t *vertices=nullptr)
void CloseGeometry(Option_t *option="d")
void DefaultColors()
TGeoMedium * GetMedium(const char *medium) const
TGeoVolumeAssembly * MakeVolumeAssembly(const char *name)
TGeoVolume * GetTopVolume() const
TGeoVolume * MakeEltu(const char *name, TGeoMedium *medium, Double_t a, Double_t b, Double_t dz)
virtual Int_t GetDefaultColor() const
TGeoMaterial * GetMaterial() const
void SetAngles(Double_t phi, Double_t theta, Double_t psi)
void SetDz(Double_t dz) override
TGeoNode * AddNode(TGeoVolume *vol, Int_t copy_no, TGeoMatrix *mat=nullptr, Option_t *option="") override
virtual TGeoNode * AddNode(TGeoVolume *vol, Int_t copy_no, TGeoMatrix *mat=nullptr, Option_t *option="")
void Draw(Option_t *option="") override
TGeoMaterial * GetMaterial() const
TGeoNode * GetNode(const char *name) const
virtual void SetMedium(TGeoMedium *medium)
void SetLineColor(Color_t lcolor) override
const char * GetName() const override
const char * GetTitle() const override
virtual void SetName(const char *name)
virtual void Warning(const char *method, const char *msgfmt,...) const
virtual void Error(const char *method, const char *msgfmt,...) const
virtual void Info(const char *method, const char *msgfmt,...) const
TRotation & SetYEulerAngles(Double_t phi, Double_t theta, Double_t psi)
Double_t Atof() const
const char * Data() const
void Form(const char *fmt,...)
void SetMagThetaPhi(Double_t mag, Double_t theta, Double_t phi)
void SetY(Double_t)
void Print(Option_t *option="") const override
Double_t Phi() const
Double_t Y() const
void RotateZ(Double_t)
Double_t Mag2() const
Double_t X() const
Double_t Mag() const
Double_t Theta() const
void SetX(Double_t)
TVector3 Cross(const TVector3 &) const
void SetZ(Double_t)
T Mag(const SVector< T, D > &rhs)
RVec< PromoteType< T > > abs(const RVec< T > &v)
gr SetName("gr")
TH1 * h
const long double torr
pressures
Definition: KVUnits.h:78
const long double um
Definition: KVUnits.h:68
const long double ug
Definition: KVUnits.h:75
const long double cm
Definition: KVUnits.h:66
double T(double x)
double dist(AxisAngle const &r1, AxisAngle const &r2)
void Info(const char *location, const char *fmt,...)
constexpr Double_t DegToRad()
constexpr Double_t RadToDeg()
TLine l
ClassImp(TPyArg)