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>
18#include <boost/format.hpp>
19#include <boost/foreach.hpp>
20#include <boost/algorithm/string.hpp>
21#include <G4AssemblyVolume.hh>
22#include <G4LogicalVolume.hh>
27#include <G4SubtractionSolid.hh>
30#include <G4VisAttributes.hh>
70 B2DEBUG(200,
"CsI Geometry Type: " << type);
78 G4Transform3D BrR = G4RotateZ3D(0.0);
80 int nEnc = content.getNumberNodes(
"/Enclosures/Enclosure");
82 G4AssemblyVolume* assemblyEnclosures =
new G4AssemblyVolume();
83 for (
int iEnc = 1; iEnc <= nEnc; iEnc++) {
88 assemblyEnclosures->MakeImprint(&topVolume, BrR);
91 B2INFO(
"Positions of the individual CsI crystals");
94 for (std::vector<G4VPhysicalVolume*>::iterator it = assemblyEnclosures->GetVolumesIterator();
95 i != assemblyEnclosures->TotalImprintedVolumes();
98 G4VPhysicalVolume* volume = *it;
99 string VolumeName = volume->GetName();
100 if (VolumeName.find(
"Crystal") < string::npos) {
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 <<
")");
113 G4AssemblyVolume* assembly,
114 G4Transform3D position,
118 if (iCry <= 0)
return;
121 double foilthickness = counter.getLength(
"/Wrapping/Thickness") * CLHEP::cm;
125 int nCry = content.getNumberNodes(
"/EndCapCrystals/EndCapCrystal");
127 B2ERROR(
"CsiCreator: Crystal index too high");
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;
143 string strMatCrystal = counter.getString(
"Material",
"Air");
147 G4VisAttributes* CrystalVisAtt =
new G4VisAttributes(G4Colour(1.0, 1.0, 0.0, 1.0));
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);
158 double fwtrapangle1 =
atan(2 * h1 / (bl1 - tl1));
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;
167 double foilhalflength = halflength + foilthickness;
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(),
177 Crystal->SetVisAttributes(CrystalVisAtt);
184 G4Trap* Foilout =
new G4Trap((format(
"Foilout_%1%") % iCry).str().c_str(),
185 foilhalflength, 0, 0, foilh1, foilbl1,
186 foiltl1, alpha1, foilh2, foilbl2,
189 G4Trap* Foilin =
new G4Trap((format(
"solidEclCrystal_%1%") % iCry).str().c_str(),
193 G4SubtractionSolid* FoilShape =
new G4SubtractionSolid((format(
"sFoil_%1%") % iCry).str().c_str(),
196 G4LogicalVolume* Foil =
new G4LogicalVolume(FoilShape, foilMaterial,
197 (format(
"Foil_%1%") % iCry).str().c_str(),
200 G4VisAttributes* FoilVisAtt =
new G4VisAttributes(G4Colour(0.1, 0.1, 0.1, 0.5));
201 Foil->SetVisAttributes(FoilVisAtt);
204 Foil->SetVisAttributes(G4VisAttributes::GetInvisible());
206 assembly->AddPlacedVolume(Crystal, position);
207 assembly->AddPlacedVolume(Foil, position);
216 string gearPath =
"Enclosures/Enclosure";
217 int nEnclosures = content.getNumberNodes(gearPath);
219 if (iEnclosure > nEnclosures) {
220 B2ERROR(
"Enclosure index too high");
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;
234 string strMatEnclosure = content.getString(
"Enclosures/Material",
"5052-Alloy");
237 string strMatEncloLid = content.getString(
"Enclosures/LidMaterial",
"5052-Alloy");
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);
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);
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();
257 GearDir enclosureContent(content);
258 enclosureContent.
append(enclosurePath);
261 G4LogicalVolume* logiEnclosure =
new G4LogicalVolume(enclosureShape, EnclosureMat, logiVolName, 0, 0, 0);
262 G4LogicalVolume* logiEncloLid =
new G4LogicalVolume(lid, EncloLidMat, logiLidVolName, 0, 0, 0);
265 double PosZ = enclosureContent.
getLength(
"PosZ") * CLHEP::cm;
266 double PosR = enclosureContent.
getLength(
"PosR") * CLHEP::cm;
267 double PosT = enclosureContent.
getAngle(
"PosT") ;
270 double Phi1 = enclosureContent.
getAngle(
"AngPhi1") ;
271 double Theta = enclosureContent.
getAngle(
"AngTheta") ;
272 double Phi2 = enclosureContent.
getAngle(
"AngPhi2") ;
275 double AdjX = enclosureContent.
getLength(
"ShiftX") * CLHEP::cm;
276 double AdjY = enclosureContent.
getLength(
"ShiftY") * CLHEP::cm;
277 double AdjZ = enclosureContent.
getLength(
"ShiftZ") * CLHEP::cm;
279 G4Transform3D zsh = 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);
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;
294 G4VisAttributes* VisAtt =
new G4VisAttributes(G4Colour(1.0, 0.5, 0.0, 0.5));
295 logiEnclosure->SetVisAttributes(VisAtt);
297 G4VisAttributes* LidVisAtt =
new G4VisAttributes(G4Colour(0.8, 1.0, 0.4, 0.5));
298 logiEncloLid->SetVisAttributes(LidVisAtt);
301 B2INFO(
"CsIBox No. " << iEnclosure <<
" Nominal pos. (mm): " << ZshTr.getTranslation());
302 B2INFO(
" Installed pos. (mm): " << ZshTrAdj.getTranslation());
303 B2INFO(
" Rotation matrix : " << ZshTrAdj.getRotation());
306 assembly->AddPlacedVolume(logiEnclosure, ZshTrAdj);
307 assembly->AddPlacedVolume(logiEncloLid, LidTrAdj);
312 for (
int iSlot = 1; iSlot <= nSlots; iSlot++) {
314 string slotPath = (format(
"/Enclosures/Slot[%1%]") % iSlot).str();
317 slotContent.
append(slotPath);
319 double SlotX = slotContent.
getLength(
"PosX") * CLHEP::cm;
320 double SlotY = slotContent.
getLength(
"PosY") * CLHEP::cm;
321 double SlotZ = slotContent.
getLength(
"PosZ") * CLHEP::cm;
324 G4Transform3D Pos = G4Translate3D(SlotX, SlotY, SlotZ);
326 int CryID = enclosureContent.
getInt((format(
"/CrystalInSlot[%1%]") % iSlot).str());
328 PutCrystal(content, assembly, adjust * Tr * Pos, iEnclosure, CryID);
GearDir is the basic class used for accessing the parameter store.
void append(const std::string &path)
Append something to the current path, modifying the GearDir in place.
virtual int getNumberNodes(const std::string &path="") const override
Return the number of nodes a given path will expand to.
virtual ~CsiCreator()
Destructor.
void BuildEnclosure(const GearDir &content, G4AssemblyVolume *assembly, std::string side, int iEnclosure)
Builds the crystals enclosures.
void PutCrystal(const GearDir &content, G4AssemblyVolume *assembly, G4Transform3D position, int iEnclosure, int iCry)
Builds the crystals and their wrapping (foil)
virtual void create(const GearDir &content, G4LogicalVolume &topVolume, geometry::GeometryTypes type)
Creation of the detector geometry from Gearbox (XML).
SensitiveDetector * m_sensitive
SensitiveDetector CSI.
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.
double getLength(const std::string &path="") const noexcept(false)
Get the parameter path as a double converted to the standard length unit.
int getInt(const std::string &path="") const noexcept(false)
Get the parameter path as a int.
static G4Material * get(const std::string &name)
Find given material.
double atan(double a)
atan for double
const double avoidov
foil inside is a little bit lager than crystal to avoid overlap
geometry::CreatorFactory< CsiCreator > CsiFactory("CSICreator")
Creator creates the CSI geometry.
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.