SToGS
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
SToGS_AGATA.cc
Go to the documentation of this file.
1 //
2 // ********************************************************************
3 // * License and Disclaimer *
4 // * *
5 // * The Geant4 software is copyright of the Copyright Holders of *
6 // * the Geant4 Collaboration. It is provided under the terms and *
7 // * conditions of the Geant4 Software License, included in the file *
8 // * LICENSE and available at http://cern.ch/geant4/license . These *
9 // * include a list of copyright holders. *
10 // * *
11 // * Neither the authors of this software system, nor their employing *
12 // * institutes,nor the agencies providing financial support for this *
13 // * work make any representation or warranty, express or implied, *
14 // * regarding this software system or assume any liability for its *
15 // * use. Please see the license in the file LICENSE and URL above *
16 // * for the full disclaimer and the limitation of liability. *
17 // * *
18 // * This code implementation is the result of the scientific and *
19 // * technical work of the GEANT4 collaboration. *
20 // * By using, copying, modifying or distributing the software (or *
21 // * any work based on the software) you agree to acknowledge its *
22 // * use in resulting scientific publications, and indicate your *
23 // * acceptance of all terms of the Geant4 Software license. *
24 // ********************************************************************
25 //
26 //
27 
28 // G4 includes
29 #include "G4Material.hh"
30 #include "G4Box.hh"
31 #include "G4Tubs.hh"
32 #include "G4Polyhedra.hh"
33 #include "G4Sphere.hh"
34 #include "G4GenericTrap.hh"
35 #include "G4Polycone.hh"
36 
37 #include "G4LogicalVolume.hh"
38 #include "G4AssemblyVolume.hh"
39 
40 #include "G4PVPlacement.hh"
41 #include "G4PVParameterised.hh"
42 #include "G4UserLimits.hh"
43 #include "G4VisAttributes.hh"
44 #include "G4Colour.hh"
45 #include "G4ios.hh"
46 #include "G4SubtractionSolid.hh"
47 #include "G4UnionSolid.hh"
48 #include "G4IntersectionSolid.hh"
49 
50 #include "G4PhysicalVolumeStore.hh"
51 #include "G4LogicalVolumeStore.hh"
52 #include "G4SDManager.hh"
53 #include "G4UnitsTable.hh"
54 
55 #include <stdlib.h>
56 
57 // Project includes
58 #include "SToGS_AGATA.hh"
59 
60 #include "SToGS_DetectorFactory.hh"
63 
64 #define L_DEBUG 1
65 
66 using namespace std;
67 
68 G4VSolid *SToGS::AGATA::AGATAShaper(G4Polycone *polycone,
69  G4double *xfront, G4double *yfront, G4double *xback, G4double *yback,
70  G4double zback,
71  G4double added_dilatation)
72 {
73  G4String name = polycone->GetName(), tmp;
74 
75  const G4int nb_edges = 6;
76  G4double lxfront[nb_edges], lyfront[nb_edges], lxback[nb_edges], lyback[nb_edges] /*offsetx, offsety, offsetz */;
77 
78  // apply scaling to the different shapes if required
79  if ( added_dilatation == 0.0 ) {
80  for (G4int i = 0; i < nb_edges; i++) {
81  lxfront[i] = xfront[i];
82  lyfront[i] = yfront[i];
83  lxback[i] = xback[i];
84  lyback[i] = yback[i];
85  }
86  }
87  else {
88  G4double D;
89  for (G4int i = 0; i < nb_edges; i++) {
90  D = std::sqrt( xfront[i]*xfront[i] + yfront[i]*yfront[i] );
91  lxfront[i] = xfront[i] + added_dilatation*xfront[i]/D ;
92  lyfront[i] = yfront[i] + added_dilatation*yfront[i]/D ;
93  D = std::sqrt( xback[i]*xback[i] + yback[i]*yback[i] );
94  lxback[i] = xback[i] + added_dilatation*xback[i]/D ;
95  lyback[i] = yback[i] + added_dilatation*yback[i]/D ;
96  }
97  }
98  // for each side of the hexagone, computes from the given point to remove an 'infinite' box [edge]
99  G4double edge_length_x = 40*CLHEP::mm, edge_width_y = 10*CLHEP::mm, edge_depth_z = 1.2*zback/2.;
100  G4int inext;
101 
102  G4VSolid *result = polycone;
103  for (G4int i = 0; i < nb_edges; i++) {
104 
105  // a new box [edge] to cut the polygone
106  tmp = name; tmp += "_edge_";
107  std::stringstream s1;
108  s1 << i;
109  tmp += s1.str();
110  //
111  G4Box *edge = new G4Box(tmp,edge_length_x,edge_width_y,edge_depth_z);
112 
113  // now defines the edges in 3D
114  if ( i == nb_edges-1 ) {
115  inext = 0;
116  }
117  else inext = i + 1;
118 
119  G4ThreeVector T;
120  // Compute the 3D vector that goes from middle of front segment to middle of back segment
121  // --> this gives the rotatation angle the edge should be rotated alongst X
122  G4ThreeVector v_RotX_1((lxback[i]+lxback[inext])/2.-(lxfront[i]+lxfront[inext])/2.,
123  (lyback[i]+lyback[inext])/2.-(lyfront[i]+lyfront[inext])/2.,zback);
124 
125  // compute 2D vector at the center of the segment
126  // --> it is used to determine the additional offset in X,Y
127  // in order to have the face of the box tangent to the surface extracted from the face of the hexagone
128  G4ThreeVector v_RotZ_0(lxfront[inext]+lxfront[i],lyfront[inext]+lyfront[i] , 0 );
129  // compute 2D vector going from i -> inext.
130  // --> it is used to detemine the rotation angle along Z for the box
131  G4ThreeVector v_RotZ_1(lxfront[inext]-lxfront[i],lyfront[inext]-lyfront[i] , 0 );
132 
133  // the total rotation matrix on the edge
134  G4RotationMatrix R;
135  R.set(0,0,0);
136  R.rotateX(v_RotX_1.theta());
137  R.rotateZ(v_RotZ_1.phi());
138  // the translation to bring the edge at the center of the cylinder
139  T.setX( (lxback[inext]+lxfront[i])/2. );
140  T.setY( (lyback[inext]+lyfront[i])/2. );
141  T.setZ( zback / 2. );
142  // the additionnal offset to take into account the wdth of the edge
143  G4ThreeVector offset( std::cos(v_RotZ_0.phi())*edge_width_y, std::sin(v_RotZ_0.phi())*edge_width_y , 0 );
144 
145 #ifdef L_DEBUG
146  G4cout << "Building Edges " << tmp << G4endl;
147  G4cout << " hexogone def @ 0 and " << zback
148  << " " << lxfront[i] << " " << lyfront[i] << " " << lxback[i] << " " << lyback[i] << G4endl;
149  G4cout << " RotX[theta] " << v_RotX_1.theta()/CLHEP::deg << " RotZ[phi] " << v_RotZ_1.phi()/CLHEP::deg << G4endl;
150  G4cout << "Translation to bring to center " << T << G4endl;
151  G4cout << "Additionnal offset dur to edge width " << offset << G4endl;
152 #endif
153 
154  T = T + offset;
155 
156  tmp = name; tmp += "_step_";
157  std::stringstream s2;
158  s2 << i;
159  tmp += s2.str();
160  result = new G4SubtractionSolid(tmp, result, edge, G4Transform3D(R,T) );
161  // used for visualization
162  //result = new G4UnionSolid(tmp, result, edge, G4Transform3D((R),T) );
163  }
164 
165  return result;
166 }
167 
168 G4LogicalVolume *SToGS::AGATA::MakeAGATACapsule(G4String detname, G4String opt)
169 {
170  G4bool do_caps = true, do_passive = false; G4String tmp;
171 
172  // cotations
173  G4double px[6], py[6], pX[6], pY[6], pz[6], pZ[6]; // definition of the front/back hexagone
174 
175  G4double HoleR; // Coaxial hole with radius HoleR
176  G4double HoleL; // Hole starts at the depth HoleL
177 
178  G4double CylR; // Radius of the cylinder that is the base of the shaped crystal
179  G4double CylL; // Length of the cylinder that is the base of the shaped crystal
180  G4double CylX; // Additionnal offset
181  G4double CylY; // Additionnal offset
182  G4double CylZ; // Additionnal offset
183 
184  G4double ThickB; // Thickness of the passive area (back)
185  G4double ThickC; // Thickness of the passive area (coaxial)
186  G4double CapS; // The crystal-encapsulation spacing is capS
187  G4double CapT; // The capsule is capT thick
188  G4double Tolerance; // CapS+CapT+tol
189 
190  G4double ColX; // RGB color components
191  G4double ColY; // RGB color components
192  G4double ColZ; // RGB color components
193 
194  G4double eps = 0.*CLHEP::mm;
195  // to avoid overlapping in G4, add/remove atrificially this quantities at borders between caps and Ge
196 
197  // file to read cotations
198  ifstream infil; infil.open(faSolid.data());
199  if ( !infil.is_open() ) {
200  G4cout << "[SToGS] *** Cannot open file " << faSolid.data() << endl; // end read the file.
201  return 0x0 ;
202  }
203 
204  // Options: bare -> no capsules, passive -> add passive
205  G4int which_id = 0;
206  if ( detname.contains("Green") ) {
207  which_id = 1;
208  }
209  if ( detname.contains("Blue") ) {
210  which_id = 2;
211  }
212  if ( opt.contains("bare") )
213  do_caps = false;
214  // if ( detname.contains("passive") )
215  // which_id = 2;
216 
217  int i1,i2,i3, nb_line = 0, nb_point = 0; double x,y,z,X,Y,Z; std::string line;
218  while( infil.good() ) {
219 
220  getline(infil,line);
221  //
222  if ( line.size() < 2u )
223  continue;
224  if ( line[0] == '#' )
225  continue;
226 
227  // decode the line
228  if(sscanf(line.data(),"%d %d %d %lf %lf %lf %lf %lf %lf", &i1, &i2, &i3, &x, &y, &z, &X, &Y, &Z) != 9) {
229  break;
230  }
231 
232  if(which_id != i1) { // a new crystal is being defined, so init a new ASolid structure
233  continue;
234  }
235  else nb_line++;
236 
237  if(i2==0 && i3==0) { // basic shape for the crystal
238  HoleR = x * CLHEP::mm;
239  CylR = y * CLHEP::mm;
240  CylL = z * CLHEP::mm;
241  CylX = X * CLHEP::mm;
242  CylY = Y * CLHEP::mm;
243  CylZ = Z * CLHEP::mm;
244  }
245  else if(i2==0 && i3==1) { // passive and capsule
246  HoleL = x * CLHEP::mm;
247  ThickB = y * CLHEP::mm;
248  ThickC = z * CLHEP::mm;
249  CapS = X * CLHEP::mm;
250  CapT = Y * CLHEP::mm;
251  Tolerance = Z * CLHEP::mm;
252  }
253  else if(i2==0 && i3==2) { // colors
254  ColX = x;
255  ColY = y;
256  ColZ = z;
257  }
258  else { // a new point to define the ploygon
259 
260  px[i3] = x * CLHEP::mm;
261  py[i3] = y * CLHEP::mm;
262  pX[i3] = X * CLHEP::mm;
263  pY[i3] = Y * CLHEP::mm;
264 
265  pz[i3] = z * CLHEP::mm;
266  pZ[i3] = Z * CLHEP::mm;
267 
268  nb_point++;
269  }
270  } // while good
271  infil.close();
272  G4cout << " the file " << faSolid.data() << " has been read " << endl; // end read the file.
273 
274  // use a physical as a container to describe the detector
275  G4RotationMatrix R; G4ThreeVector T; G4Transform3D Tr;
276 
277  // the coax part :
278  // the raw crystal
279  G4double *zSliceGe = new G4double[4];
280  zSliceGe[0] = (0)*CLHEP::mm;
281  zSliceGe[1] = (HoleL)*CLHEP::mm;
282  zSliceGe[2] = (HoleL+0.1)*CLHEP::mm;
283  zSliceGe[3] = (+CylL)*CLHEP::mm;
284  //
285  G4double *InnRadGe = new G4double[4];
286  InnRadGe[0] = 0.;
287  InnRadGe[1] = 0.;
288  InnRadGe[2] = HoleR*CLHEP::mm;
289  InnRadGe[3] = HoleR*CLHEP::mm;
290  //
291  G4double *OutRadGe = new G4double[4];
292  OutRadGe[0] = CylR*CLHEP::mm;
293  OutRadGe[1] = CylR*CLHEP::mm;
294  OutRadGe[2] = CylR*CLHEP::mm;
295  OutRadGe[3] = CylR*CLHEP::mm;
296  //
297  tmp = detname;
298  tmp += "_coax";
299  G4Polycone *coax = new G4Polycone(tmp, 0.*CLHEP::deg, 360.*CLHEP::deg, 4, zSliceGe, InnRadGe, OutRadGe ) ;
300  // out of the shaper, the crystal with its complex shape
301  tmp = detname;
302  tmp += "_crystal";
303  G4VSolid *crystal = AGATAShaper(coax,px,py,pX,pY,CylL);
304  crystal->SetName(tmp);
305 
306  // set attributes of the capsule and place it
307  G4LogicalVolume *crystal_logic =
308  new G4LogicalVolume(crystal,
309  SToGS::MaterialConsultant::theConsultant()->FindOrBuildMaterial("Ge"),tmp,0,0,0);
310  G4VisAttributes *crystal_visatt = new G4VisAttributes( G4Colour(ColX, ColY, ColZ,1) );
311  crystal_logic->SetVisAttributes( crystal_visatt );
312  crystal_logic->SetSensitiveDetector( SToGS::UserActionInitialization::GetCopClusterSD() );
313  // the coax part
314 
315  // encapsulation of the crystal
316  G4LogicalVolume *capsule_logic = 0x0, *spacing_logic = 0x0;
317  if (do_caps) {
318  // spacing filled with air
319  zSliceGe[0] = (0.0)*CLHEP::mm;
320  zSliceGe[1] = (CylL + 2*CapT)*CLHEP::mm;
321  //
322  InnRadGe[0] = 0.;
323  InnRadGe[1] = 0.;
324  //
325  OutRadGe[0] = (CylR + CapT)*CLHEP::mm;
326  OutRadGe[1] = (CylR + CapT)*CLHEP::mm;
327  //
328  tmp = detname;
329  tmp += "_coax_spacing";
330  G4Polycone *coax_spacing_shape = new G4Polycone(tmp, 0.*CLHEP::deg, 360.*CLHEP::deg, 2, zSliceGe, InnRadGe, OutRadGe);
331  //
332  tmp = detname;
333  tmp += "_capsule_spacing";
334  G4VSolid *spacing = AGATAShaper(coax_spacing_shape,px,py,pX,pY,CylL,CapT);
335  spacing->SetName(tmp);
336  //
337  // set attributes
338  spacing_logic = new G4LogicalVolume(spacing,
339  SToGS::MaterialConsultant::theConsultant()->FindOrBuildMaterial("AIR"),tmp,0,0,0);
340  G4VisAttributes *spacing_visatt = new G4VisAttributes( G4Colour(1, 1, 1,0.1) );
341  spacing_logic->SetVisAttributes( spacing_visatt );
342 
343  // capsule filled with Al
344  zSliceGe[0] = (0.0)*CLHEP::mm;
345  zSliceGe[1] = (2*(CapT + CapS))*CLHEP::mm;
346  //
347  InnRadGe[0] = 0.;
348  InnRadGe[1] = 0.;
349  //
350  OutRadGe[0] = (CylR + CapT + CapS)*CLHEP::mm;
351  OutRadGe[1] = (CylR + CapT + CapS)*CLHEP::mm;
352  //
353  tmp = detname;
354  tmp += "_coax_encapsulation";
355  G4Polycone *coax_caps_shape = new G4Polycone(tmp, 0.*CLHEP::deg, 360.*CLHEP::deg, 2, zSliceGe, InnRadGe, OutRadGe);
356  //
357  tmp = detname;
358  tmp += "_capsule";
359  G4VSolid *capsule = AGATAShaper(coax_caps_shape,px,py,pX,pY,CylL,(CapT+CapS));
360  capsule->SetName(tmp);
361  //
362  // set attributes
363  capsule_logic = new G4LogicalVolume(capsule,
364  SToGS::MaterialConsultant::theConsultant()->FindOrBuildMaterial("Al"),tmp,0,0,0);
365  G4VisAttributes *capsule_visatt = new G4VisAttributes( G4Colour(0.3, 0.3, 0.3, 0.6) );
366  capsule_logic->SetVisAttributes( capsule_visatt );
367  }
368 
369  if ( capsule_logic && spacing_logic ) {
370  return capsule_logic;
371  }
372 
373  return crystal_logic;
374 }
375 
376 G4AssemblyVolume *SToGS::AGATA::MakeAGATACluster(G4String opt)
377 {
378  G4AssemblyVolume *theCluster = 0x0; G4VPhysicalVolume *caps; std::vector < G4LogicalVolume * > capsules(3);
379 
380  ifstream infil; infil.open(faCluster.data());
381  if ( !infil.is_open() ) {
382  G4cout << "[SToGS] *** Cannot open file " << faCluster.data() << G4endl; // end read the file.
383  return 0x0 ;
384  }
385  //
386  capsules[0] = MakeAGATACapsule("AGATA-ARed","bare");
387  capsules[1] = MakeAGATACapsule("AGATA-BGreen","bare");
388  capsules[2] = MakeAGATACapsule("AGATA-CBlue","bare");
389  //
390  theCluster = new G4AssemblyVolume();
391 
392  G4int i1,i2,i3, nb_line = 0, which = 0; G4double x,y,z,ps, th, ph; std::string line;
393  while( infil.good() ) {
394 
395  // get euler angles from files
396  getline(infil,line);
397  //
398  if ( line.size() < 2u )
399  continue;
400  if ( line[0] == '#' )
401  continue;
402  if(sscanf(line.data(),"%d %d %d %lf %lf %lf %lf %lf %lf", &i1, &i2, &i3, &ps, &th, &ph, &x, &y, &z) != 9) {
403  break;
404  }
405 
406  G4ThreeVector T;G4RotationMatrix R; R.set(0,0,0);
407  which = i2;
408  G4String name; // name for each crystal
409  if ( which == 0 )
410  name = "ARed:0";
411  if ( which == 1 )
412  name = "BGreen:1";
413  if ( which == 2 )
414  name = "CBlue:2";
415 
416  //
417  T.setX(x*CLHEP::mm);
418  T.setY(y*CLHEP::mm);
419  T.setZ(z*CLHEP::mm);
420  //
421  R.rotateZ(G4double(ps)*CLHEP::deg);
422  R.rotateY(G4double(th)*CLHEP::deg);
423  R.rotateZ(G4double(ph)*CLHEP::deg);
424  //
425  G4Transform3D Tr(R,T) ;
426  theCluster->AddPlacedVolume( capsules[which] , Tr);
427  }
428  infil.close();
429  G4cout << " the file " << faCluster.data() << " has been read " << endl; // end read the file.
430 
431  return theCluster;
432 }
433 
434 #ifdef L_DEBUG
435 #include "G4GDMLParser.hh"
436 #endif
437 G4VPhysicalVolume* SToGS::AGATA::Construct()
438 {
439  G4VPhysicalVolume *theDetector = 0x0;
440 
441  // try to open the file
442  ifstream infil; infil.open(faEuler.data());
443  if ( !infil.is_open() )
444  return 0x0 ;
445 
446  G4LogicalVolume *detlogicWorld;
447  G4Box *detWorld;
448  detWorld = new G4Box("AGATA",2.*CLHEP::m,2.*CLHEP::m,2.*CLHEP::m);
449  detlogicWorld=
450  new G4LogicalVolume(detWorld,
451  SToGS::MaterialConsultant::theConsultant()->FindOrBuildMaterial("AIR"), "AGATA", 0, 0, 0);
452  detlogicWorld->SetVisAttributes(G4VisAttributes::Invisible); // hide the world
453  // Must place the World Physical volume unrotated at (0,0,0).
454  theDetector = new G4PVPlacement(0, // no rotation
455  G4ThreeVector(), // at (0,0,0)
456  detlogicWorld, // its logical volume
457  "AGATA", // its name
458  0, // its mother volume
459  false, // no boolean operations
460  -1); // copy number
461 
462 
463  G4cout << "\n Reading description of AGATA from file " << faEuler.data() << " ..." << endl;
464 
465  G4AssemblyVolume *cluster = MakeAGATACluster("");
466 
467  G4int i1, i2, nclust = 0; G4double ps, th, ph, x, y, z; std::string line;
468  while(infil.good()) {
469 
470  // get euler angles from files
471  getline(infil,line);
472  //
473  if ( line.size() < 2u )
474  continue;
475  if ( line[0] == '#' )
476  continue;
477  if(sscanf(line.data(),"%d %d %lf %lf %lf %lf %lf %lf", &i1, &i2, &ps, &th, &ph, &x, &y, &z) != 8)
478  break;
479 
480  G4ThreeVector T(x*CLHEP::mm,y*CLHEP::mm,z*CLHEP::mm); G4RotationMatrix R;
481  R.rotateZ(ps*CLHEP::deg);
482  R.rotateY(th*CLHEP::deg);
483  R.rotateZ(ph*CLHEP::deg);
484 
485  G4Transform3D Tr(R,T);
486  cluster->MakeImprint(detlogicWorld, Tr );
487  nclust++;;
488  }
489  infil.close();
490 
491  cout << nclust << " cluster(s) composed this geometry " << endl;
492 
493 #ifdef L_DEBUG
494  G4GDMLParser parser;
495  parser.Write("toto.gdml",detlogicWorld,false);
496 #endif
497 
498  return theDetector;
499 }
500 
501 
502 
503 
virtual G4VPhysicalVolume * Construct()
One of the mandatory class to be implemented in order to have G4 working properly.
Definition: SToGS_AGATA.cc:437
static G4VSensitiveDetector * GetCopClusterSD(G4String name="/SToGS/SD/CopCluster")
to get a general SToGS Calorimeter. In Multi-threading mode, return a new instance otherwise a global...