Belle II Software  release-08-01-10
CsiCreator.cc
1 /**************************************************************************
2  * basf2 (Belle II Analysis Software Framework) *
3  * Author: The Belle II Collaboration *
4  * *
5  * See git log for contributors and copyright holders. *
6  * This file is licensed under LGPL-3.0, see LICENSE.md. *
7  **************************************************************************/
8 
9 #include <beast/csi/geometry/CsiCreator.h>
10 #include <beast/csi/simulation/SensitiveDetector.h>
11 #include <beast/csi/geometry/CsiGeometryPar.h>
12 #include <geometry/Materials.h>
13 #include <geometry/CreatorFactory.h>
14 #include <framework/gearbox/GearDir.h>
15 #include <framework/logging/Logger.h>
16 
17 #include <cmath>
18 #include <boost/format.hpp>
19 #include <boost/foreach.hpp>
20 #include <boost/algorithm/string.hpp>
21 #include <G4AssemblyVolume.hh>
22 #include <G4LogicalVolume.hh>
23 
24 //Shapes
25 #include <G4Trap.hh>
26 #include <G4Box.hh>
27 #include <G4SubtractionSolid.hh>
28 
29 //Visualization Attributes
30 #include <G4VisAttributes.hh>
31 
32 using namespace std;
33 using namespace boost;
34 
35 
36 namespace Belle2 {
43  namespace csi {
44 
45  // Register the creator
48 
49  // add foil thickness //
50  const double avoidov = 1 + 1E-6;
52 
53 
54  CsiCreator::CsiCreator(): m_sensitive(0)
55  {
56  //m_sensitive = new SensitiveDetector();
57  }
58 
60  {
61  if (m_sensitive) delete m_sensitive;
62  }
63 
64  void CsiCreator::create(const GearDir& content, G4LogicalVolume& topVolume, geometry::GeometryTypes type)
65  {
66 
68 
69  //Print the type (not used for now)
70  B2DEBUG(200, "CsI Geometry Type: " << type);
71 
72  // Print list of defined materials
73  /*
74  G4NistManager* nistManager = G4NistManager::Instance();
75  cout << *(G4Material::GetMaterialTable()) << endl;
76  */
77 
78  G4Transform3D BrR = G4RotateZ3D(0.0);
79 
80  int nEnc = content.getNumberNodes("/Enclosures/Enclosure");
81 
82  G4AssemblyVolume* assemblyEnclosures = new G4AssemblyVolume();
83  for (int iEnc = 1; iEnc <= nEnc; iEnc++) {
84  BuildEnclosure(content, assemblyEnclosures, "side", iEnc);
85  //
86  }
87 
88  assemblyEnclosures->MakeImprint(&topVolume, BrR);
89 
90  // Show cell IDs and volume names
91  B2INFO("Positions of the individual CsI crystals");
93  unsigned int i = 0;
94  for (std::vector<G4VPhysicalVolume*>::iterator it = assemblyEnclosures->GetVolumesIterator();
95  i != assemblyEnclosures->TotalImprintedVolumes();
96  ++it, ++i) {
97 
98  G4VPhysicalVolume* volume = *it;
99  string VolumeName = volume->GetName();
100  if (VolumeName.find("Crystal") < string::npos) {
101  B2INFO("Crystal Number " << eclp->CsiVolNameToCellID(VolumeName) <<
102  " placed at (r[cm],[deg],z[cm]) = (" << setprecision(1) << fixed <<
103  volume->GetTranslation().perp() / CLHEP::cm << "," <<
104  volume->GetTranslation().phi() * 180.0 / M_PI << "," <<
105  volume->GetTranslation().z() / CLHEP::cm << ")");
106  }
107 
108 
109  }// for all physical volumes in the assembly
110  }// create
111 
112  void CsiCreator::PutCrystal(const GearDir& content,
113  G4AssemblyVolume* assembly,
114  G4Transform3D position,
115  int iEnclosure,
116  int iCry)
117  {
118  if (iCry <= 0) return;
119 
120  GearDir counter(content);
121  double foilthickness = counter.getLength("/Wrapping/Thickness") * CLHEP::cm;
122  G4Material* foilMaterial = geometry::Materials::get(counter.getString("/Wrapping/Material"));
123 
124 
125  int nCry = content.getNumberNodes("/EndCapCrystals/EndCapCrystal");
126  if (iCry > nCry) {
127  B2ERROR("CsiCreator: Crystal index too high");
128  return ;
129  }
130 
131  counter.append((format("/EndCapCrystals/EndCapCrystal[%1%]/") % (iCry)).str());
132  double h1 = counter.getLength("K_h1") * CLHEP::cm;
133  double h2 = counter.getLength("K_h2") * CLHEP::cm;
134  double bl1 = counter.getLength("K_bl1") * CLHEP::cm;
135  double bl2 = counter.getLength("K_bl2") * CLHEP::cm;
136  double tl1 = counter.getLength("K_tl1") * CLHEP::cm;
137  double tl2 = counter.getLength("K_tl2") * CLHEP::cm;
138  double alpha1 = counter.getAngle("K_alpha1");
139  double alpha2 = counter.getAngle("K_alpha2");
140  double halflength = counter.getLength("k_HalfLength") * CLHEP::cm;
141 
142  // Read and create material
143  string strMatCrystal = counter.getString("Material", "Air");
144  G4Material* crystalMaterial = geometry::Materials::get(strMatCrystal);
145 
146 
147  G4VisAttributes* CrystalVisAtt = new G4VisAttributes(G4Colour(1.0, 1.0, 0.0, 1.0));
148 
149  if (strMatCrystal.compare("CsI") == 0) {
150  CrystalVisAtt->SetColour(18.0 / 256, 230.0 / 256, 3.0 / 256);
151  } else if (strMatCrystal.compare("CsI-Tl") == 0) {
152  CrystalVisAtt->SetColour(0.0, 0.5, 1.0);
153  } else if (strMatCrystal.compare("LYSO") == 0) {
154  CrystalVisAtt->SetColour(0.820, 0.148, 0.1875);
155  }
156 
158  double fwtrapangle1 = atan(2 * h1 / (bl1 - tl1)); // the smaller angle of the trap
159  double fwtrapangle2 = atan(2 * h2 / (bl2 - tl2));
160  double foilh1 = h1 + foilthickness;
161  double foilh2 = h2 + foilthickness;
162  double foiltl1 = tl1 + foilthickness * tan(fwtrapangle1 / 2);
163  double foilbl1 = bl1 + foilthickness / tan(fwtrapangle1 / 2);
164  double foiltl2 = tl2 + foilthickness * tan(fwtrapangle2 / 2);
165  double foilbl2 = foiltl2 + (foilbl1 - foiltl1) * foilh2 / foilh1;
166 
167  double foilhalflength = halflength + foilthickness;
169 
170  string cryLogiVolName = (format("Enclosure_%1%_Crystal_%2%") % iEnclosure % iCry).str();
171  G4Trap* CrystalShape = new G4Trap((format("sCrystal_%1%") % iCry).str().c_str(),
172  halflength, 0, 0, h1, bl1, tl1, alpha1, h2, bl2, tl2, alpha2);
173  G4LogicalVolume* Crystal = new G4LogicalVolume(CrystalShape, crystalMaterial,
174  cryLogiVolName.c_str(),
175  0, 0, 0);
176 
177  Crystal->SetVisAttributes(CrystalVisAtt);
178  Crystal->SetSensitiveDetector(m_sensitive);
179 
180  //cout << "CSI volume " << CrystalShape->GetCubicVolume() / CLHEP::cm / CLHEP::cm / CLHEP::cm
181  //<< " density " << crystalMaterial->GetDensity() / CLHEP::g * CLHEP::cm * CLHEP::cm * CLHEP::cm << endl;
182 
184  G4Trap* Foilout = new G4Trap((format("Foilout_%1%") % iCry).str().c_str(),
185  foilhalflength, 0, 0, foilh1, foilbl1,
186  foiltl1, alpha1, foilh2, foilbl2,
187  foiltl2, alpha2);
188 
189  G4Trap* Foilin = new G4Trap((format("solidEclCrystal_%1%") % iCry).str().c_str(),
190  halflength * avoidov, 0, 0, h1 * avoidov,
191  bl1 * avoidov, tl1 * avoidov, alpha1, h2 * avoidov,
192  bl2 * avoidov, tl2 * avoidov, alpha2);
193  G4SubtractionSolid* FoilShape = new G4SubtractionSolid((format("sFoil_%1%") % iCry).str().c_str(),
194  Foilout, Foilin);
195 
196  G4LogicalVolume* Foil = new G4LogicalVolume(FoilShape, foilMaterial,
197  (format("Foil_%1%") % iCry).str().c_str(),
198  0, 0, 0);
199 
200  G4VisAttributes* FoilVisAtt = new G4VisAttributes(G4Colour(0.1, 0.1, 0.1, 0.5));
201  Foil->SetVisAttributes(FoilVisAtt);
202 
203  //Hide the foils for now...
204  Foil->SetVisAttributes(G4VisAttributes::GetInvisible());
205 
206  assembly->AddPlacedVolume(Crystal, position);
207  assembly->AddPlacedVolume(Foil, position);
208 
209  return ;
210 
211  }
212 
213  void CsiCreator::BuildEnclosure(const GearDir& content, G4AssemblyVolume* assembly, const string side, int iEnclosure)
214  {
215 
216  string gearPath = "Enclosures/Enclosure";
217  int nEnclosures = content.getNumberNodes(gearPath);
218 
219  if (iEnclosure > nEnclosures) {
220  B2ERROR("Enclosure index too high");
221  return ;
222  }
223 
224  // Build the box (same for all)
225  double width = content.getLength("Enclosures/Width") * CLHEP::cm;
226  double length = content.getLength("Enclosures/Length") * CLHEP::cm;
227  double depth = content.getLength("Enclosures/Depth") * CLHEP::cm;
228  double thk = content.getLength("Enclosures/Thickness") * CLHEP::cm;
229  double fold = content.getLength("Enclosures/Fold") * CLHEP::cm;
230  double lidthk = content.getLength("Enclosures/LidThickness") * CLHEP::cm;
231  double halflength = 15.0 * CLHEP::cm;
232  double zshift = 0.5 * length - thk - halflength; /*< Shift of the box along z-axis to make crystal touch the panel **/
233 
234  string strMatEnclosure = content.getString("Enclosures/Material", "5052-Alloy");
235  G4Material* EnclosureMat = geometry::Materials::get(strMatEnclosure);
236 
237  string strMatEncloLid = content.getString("Enclosures/LidMaterial", "5052-Alloy");
238  G4Material* EncloLidMat = geometry::Materials::get(strMatEncloLid);
239 
240  G4Box* outer = new G4Box("Outer", 0.5 * width, 0.5 * depth, 0.5 * length);
241  G4Box* inner = new G4Box("Inner", 0.5 * width - thk, 0.5 * depth - thk, 0.5 * length - thk);
242  G4Box* opening = new G4Box("Opening", 0.5 * width - fold, 0.5 * depth, 0.5 * length - fold);
243  G4Box* lid = new G4Box("Lid", 0.5 * width, 0.5 * lidthk, 0.5 * length);
244 
245  G4ThreeVector translation(0, thk, 0);
246  G4Translate3D transform(translation);
247  G4SubtractionSolid* enclosureShapeT = new G4SubtractionSolid("EnclosureShapeT", outer, inner);
248  G4SubtractionSolid* enclosureShape = new G4SubtractionSolid("EnclosureShape",
249  enclosureShapeT, opening, transform);
250 
251  //Thread the strings
252  string enclosurePath = (format("/%1%[%2%]") % gearPath % iEnclosure).str();
253  string logiVolName = (format("%1%Enclosure_%2%") % side % iEnclosure).str();
254  string logiLidVolName = (format("%1%EnclosureLid_%2%") % side % iEnclosure).str();
255 
256  // Connect the appropriate Gearbox path
257  GearDir enclosureContent(content);
258  enclosureContent.append(enclosurePath);
259 
260  // Create logical volumes
261  G4LogicalVolume* logiEnclosure = new G4LogicalVolume(enclosureShape, EnclosureMat, logiVolName, 0, 0, 0);
262  G4LogicalVolume* logiEncloLid = new G4LogicalVolume(lid, EncloLidMat, logiLidVolName, 0, 0, 0);
263 
264  // Read position
265  double PosZ = enclosureContent.getLength("PosZ") * CLHEP::cm;
266  double PosR = enclosureContent.getLength("PosR") * CLHEP::cm;
267  double PosT = enclosureContent.getAngle("PosT") ;
268 
269  // Read Orientation
270  double Phi1 = enclosureContent.getAngle("AngPhi1") ;
271  double Theta = enclosureContent.getAngle("AngTheta") ;
272  double Phi2 = enclosureContent.getAngle("AngPhi2") ;
273 
274  //Read position adjustments from nominal
275  double AdjX = enclosureContent.getLength("ShiftX") * CLHEP::cm;
276  double AdjY = enclosureContent.getLength("ShiftY") * CLHEP::cm;
277  double AdjZ = enclosureContent.getLength("ShiftZ") * CLHEP::cm;
278 
279  G4Transform3D zsh = G4Translate3D(0, 0, zshift);
280  //G4Transform3D invzsh = G4Translate3D(0, 0, -zshift);
281  G4Transform3D m1 = G4RotateZ3D(Phi1);
282  G4Transform3D m2 = G4RotateY3D(Theta);
283  G4Transform3D m3 = G4RotateZ3D(Phi2);
284  G4Transform3D position = G4Translate3D(PosR * cos(PosT), PosR * sin(PosT), PosZ);
285  G4Transform3D adjust = G4Translate3D(AdjX, AdjY, AdjZ);
286  G4Transform3D lidpos = G4Translate3D(0, 0.5 * (depth + lidthk), 0);
287 
288  G4Transform3D Tr = position * m3 * m2 * m1;
289  G4Transform3D ZshTr = Tr * zsh;
290  G4Transform3D ZshTrAdj = adjust * ZshTr;
291  G4Transform3D LidTr = ZshTr * lidpos;
292  G4Transform3D LidTrAdj = adjust * LidTr;
293 
294  G4VisAttributes* VisAtt = new G4VisAttributes(G4Colour(1.0, 0.5, 0.0, 0.5));
295  logiEnclosure->SetVisAttributes(VisAtt);
296 
297  G4VisAttributes* LidVisAtt = new G4VisAttributes(G4Colour(0.8, 1.0, 0.4, 0.5));
298  logiEncloLid->SetVisAttributes(LidVisAtt);
299  //logiEncloLid->SetVisAttributes(G4VisAttributes::GetInvisible());
300 
301  B2INFO("CsIBox No. " << iEnclosure << " Nominal pos. (mm): " << ZshTr.getTranslation());
302  B2INFO(" Installed pos. (mm): " << ZshTrAdj.getTranslation());
303  B2INFO(" Rotation matrix : " << ZshTrAdj.getRotation());
304  B2INFO(" ");
305 
306  assembly->AddPlacedVolume(logiEnclosure, ZshTrAdj);
307  assembly->AddPlacedVolume(logiEncloLid, LidTrAdj);
308 
309 
310  int nSlots = enclosureContent.getNumberNodes("CrystalInSlot");
311 
312  for (int iSlot = 1; iSlot <= nSlots; iSlot++) {
313  //Thread the strings
314  string slotPath = (format("/Enclosures/Slot[%1%]") % iSlot).str();
315 
316  GearDir slotContent(content);
317  slotContent.append(slotPath);
318 
319  double SlotX = slotContent.getLength("PosX") * CLHEP::cm;
320  double SlotY = slotContent.getLength("PosY") * CLHEP::cm;
321  double SlotZ = slotContent.getLength("PosZ") * CLHEP::cm;
322 
323 
324  G4Transform3D Pos = G4Translate3D(SlotX, SlotY, SlotZ);
325 
326  int CryID = enclosureContent.getInt((format("/CrystalInSlot[%1%]") % iSlot).str());
327 
328  PutCrystal(content, assembly, adjust * Tr * Pos, iEnclosure, CryID);
329  }
330 
331  return;
332 
333  }
334 
335  } // csi namespace
337 } // Belle2 namespace
R E
internal precision of FFTW codelets
GearDir is the basic class used for accessing the parameter store.
Definition: GearDir.h:31
void append(const std::string &path)
Append something to the current path, modifying the GearDir in place.
Definition: GearDir.h:52
virtual int getNumberNodes(const std::string &path="") const override
Return the number of nodes a given path will expand to.
Definition: GearDir.h:58
virtual ~CsiCreator()
Destructor.
Definition: CsiCreator.cc:59
void BuildEnclosure(const GearDir &content, G4AssemblyVolume *assembly, std::string side, int iEnclosure)
Builds the crystals enclosures.
Definition: CsiCreator.cc:213
void PutCrystal(const GearDir &content, G4AssemblyVolume *assembly, G4Transform3D position, int iEnclosure, int iCry)
Builds the crystals and their wrapping (foil)
Definition: CsiCreator.cc:112
virtual void create(const GearDir &content, G4LogicalVolume &topVolume, geometry::GeometryTypes type)
Creation of the detector geometry from Gearbox (XML).
Definition: CsiCreator.cc:64
SensitiveDetector * m_sensitive
SensitiveDetector CSI.
Definition: CsiCreator.h:49
The Class for CSI Geometry Parameters.
static CsiGeometryPar * Instance()
Static method to get a reference to the CsiGeometryPar instance.
int CsiVolNameToCellID(const G4String VolumeName)
Get Cell Id.
Sensitive Detector implementation of the CSI detector.
double getAngle(const std::string &path="") const noexcept(false)
Get the parameter path as a double converted to the standard angle unit.
Definition: Interface.h:299
double getLength(const std::string &path="") const noexcept(false)
Get the parameter path as a double converted to the standard length unit.
Definition: Interface.h:259
int getInt(const std::string &path="") const noexcept(false)
Get the parameter path as a int.
Definition: Interface.cc:60
static G4Material * get(const std::string &name)
Find given material.
Definition: Materials.h:63
double atan(double a)
atan for double
Definition: beamHelpers.h:34
double tan(double a)
tan for double
Definition: beamHelpers.h:31
geometry::CreatorFactory< CsiCreator > CsiFactory("CSICreator")
Creator creates the CSI geometry.
const double avoidov
foil inside is a little bit lager than crystal to avoid overlap
Definition: CsiCreator.cc:50
GeometryTypes
Flag indiciating the type of geometry to be used.
Abstract base class for different kinds of events.
Very simple class to provide an easy way to register creators with the CreatorManager.