The key method in this class; creates a parallel world view of those volumes relevant to the LAr voxel readout. Required of any class that inherits from G4VUserParallelWorld
have some sorting...
144 G4VPhysicalVolume* parallelPhysical = GetWorld();
152 G4Transform3D worldTransform;
155 std::string daughterName(
"volDetEnclosure");
156 G4Transform3D detEnclosureTransform;
159 detEnclosureTransform,
166 struct VoxelSpecs_t {
168 unsigned int nw, nh, nd;
171 bool operator< (
const VoxelSpecs_t& vs)
const 173 if (w < vs.w)
return true;
174 if (w > vs.w)
return false;
175 if (h < vs.h)
return true;
176 if (h > vs.h)
return false;
177 if (d < vs.d)
return true;
178 if (d > vs.d)
return false;
179 if (nw < vs.nw)
return true;
180 if (nw > vs.nw)
return false;
181 if (nh < vs.nh)
return true;
182 if (nh > vs.nh)
return false;
183 if (nd < vs.nd)
return true;
189 struct VoxelVolumes_t {
190 G4LogicalVolume* pBox;
191 G4LogicalVolume* pCell;
194 (G4LogicalVolume* box =
nullptr, G4LogicalVolume* cell =
nullptr):
195 pBox(box), pCell(cell) {}
202 LArVoxelReadout* larVoxelReadout =
new LArVoxelReadout(
"LArVoxelSD");
205 larVoxelReadout->SetSingleTPC(0, 0);
209 G4SDManager* sdManager = G4SDManager::GetSDMpointer();
210 sdManager->AddNewDetector(larVoxelReadout);
213 typedef std::map<VoxelSpecs_t, VoxelVolumes_t> VoxelCache_t;
214 VoxelCache_t VoxelCache;
219 daughterName =
"volCryostat";
220 G4Transform3D cryostatTransform;
221 G4VPhysicalVolume* cryostatVolume = this->
FindNestedVolume(detEnclosureVolume,
222 detEnclosureTransform,
230 daughterName =
"volTPC";
231 G4Transform3D tpcTransform;
238 daughterName =
"volTPCActive";
239 G4Transform3D transform;
247 G4LogicalVolume* larTPCLogical = larTPCPhysical->GetLogicalVolume();
248 larTPCLogical->SetUserLimits(
fStepLimit.get());
250 G4VSolid* larTPCShape = larTPCLogical->GetSolid();
262 G4double larTPCHalfXLength = 0;
263 G4double larTPCHalfYLength = 0;
264 G4double larTPCHalfZLength = 0;
265 G4Box* tpcBox =
dynamic_cast< G4Box*
>( larTPCShape );
267 larTPCHalfXLength = tpcBox->GetXHalfLength();
268 larTPCHalfYLength = tpcBox->GetYHalfLength();
269 larTPCHalfZLength = tpcBox->GetZHalfLength();
273 G4Tubs* tube =
dynamic_cast< G4Tubs*
>( larTPCShape );
275 larTPCHalfXLength = tube->GetOuterRadius();
276 larTPCHalfYLength = tube->GetOuterRadius();
277 larTPCHalfZLength = tube->GetZHalfLength();
280 throw cet::exception(
"LArVoxelReadoutGeometry") <<
"Unknown shape in readout geometry" 281 <<
"The LAr TPC volume is not a box or a tube. " 282 <<
"This routine can't convert any other shapes.\n";
286 LOG_DEBUG(
"LArVoxelReadoutGeometry") <<
": larTPCHalfXLength=" << larTPCHalfXLength
287 <<
": larTPCHalfYLength=" << larTPCHalfYLength
288 <<
": larTPCHalfZLength=" << larTPCHalfZLength;
296 G4double voxelOffsetX = lvc->
VoxelOffsetX() * CLHEP::cm;
297 G4double voxelOffsetY = lvc->
VoxelOffsetY() * CLHEP::cm;
298 G4double voxelOffsetZ = lvc->
VoxelOffsetZ() * CLHEP::cm;
300 LOG_DEBUG(
"LArVoxelReadoutGeometry") <<
": voxelSizeX=" << voxelSizeX
301 <<
", voxelSizeY=" << voxelSizeY
304 LOG_DEBUG(
"LArVoxelReadoutGeometry") <<
": voxelOffsetX=" << voxelOffsetX
305 <<
", voxelOffsetY=" << voxelOffsetY
306 <<
", voxelOffsetZ=" << voxelOffsetZ;
315 G4double numberXvoxels = 2.*larTPCHalfXLength /
voxelSizeX;
316 G4double numberYvoxels = 2.*larTPCHalfYLength /
voxelSizeY;
317 G4double numberZvoxels = 2.*larTPCHalfZLength /
voxelSizeZ;
318 numberXvoxels = trunc(numberXvoxels) + 1.;
319 numberYvoxels = trunc(numberYvoxels) + 1.;
320 numberZvoxels = trunc(numberZvoxels) + 1.;
322 LOG_DEBUG(
"LArVoxelReadoutGeometry") <<
"Active volume of cryo #" << c <<
" TPC #" << t
323 <<
" will be split in " << numberXvoxels <<
" x " << numberYvoxels <<
" x " << numberZvoxels
324 <<
" = " << (numberXvoxels * numberYvoxels * numberZvoxels)
325 <<
" voxels of size " << voxelSizeX <<
" x " << voxelSizeY <<
" x " << voxelSizeZ <<
" cm" 328 VoxelSpecs_t VoxelSpecs{
329 2.*larTPCHalfXLength,
330 2.*larTPCHalfYLength,
331 2.*larTPCHalfZLength,
332 (
unsigned int) numberXvoxels,
333 (
unsigned int) numberYvoxels,
334 (
unsigned int) numberZvoxels
338 VoxelCache.end(): VoxelCache.find(VoxelSpecs);
339 if (iVoxelVol == VoxelCache.end()) {
340 LOG_DEBUG(
"LArVoxelReadoutGeometry") <<
"Creating a new voxel volume " 341 << VoxelSpecs.w <<
" x " << VoxelSpecs.h <<
" x " << VoxelSpecs.d
343 << VoxelSpecs.nw <<
" x " << VoxelSpecs.nh <<
" x " << VoxelSpecs.nd
346 G4double voxelBoxHalfX = numberXvoxels * voxelSizeX / 2.;
347 G4double voxelBoxHalfY = numberYvoxels * voxelSizeY / 2.;
348 G4double voxelBoxHalfZ = numberZvoxels * voxelSizeZ / 2.;
350 LOG_DEBUG(
"LArVoxelReadoutGeometry") <<
": voxelBoxHalfX=" << voxelBoxHalfX
351 <<
", voxelBoxHalfY=" << voxelBoxHalfY
352 <<
", voxelBoxHalfZ=" << voxelBoxHalfZ;
357 G4Box* voxelBox =
new G4Box(
"VoxelBox",voxelBoxHalfX,voxelBoxHalfY,voxelBoxHalfZ);
358 G4LogicalVolume* voxelBoxLogical =
new G4LogicalVolume(voxelBox,
360 "VoxelizationLogicalVolume" );
364 G4VisAttributes* invisible =
new G4VisAttributes();
365 invisible->SetVisibility(
false);
366 voxelBoxLogical->SetVisAttributes(invisible);
380 G4Box* xSlice =
new G4Box(
"xSlice",voxelSizeX/2.,voxelBoxHalfY,voxelBoxHalfZ);
381 G4LogicalVolume* xSliceLogical =
new G4LogicalVolume( xSlice, 0,
"xLArVoxelSlice" );
382 xSliceLogical->SetVisAttributes(invisible);
385 new G4PVReplica(
"VoxelSlicesInX",
389 G4int( numberXvoxels ),
393 G4Box* ySlice =
new G4Box(
"ySlice",voxelSizeX/2.,voxelSizeY/2., voxelBoxHalfZ);
394 G4LogicalVolume* ySliceLogical =
new G4LogicalVolume( ySlice, 0,
"yLArVoxelSlice" );
395 ySliceLogical->SetVisAttributes(invisible);
396 new G4PVReplica(
"VoxelSlicesInY",
400 G4int( numberYvoxels ),
404 G4Box* zSlice =
new G4Box(
"zSlice",voxelSizeX/2.,voxelSizeY/2., voxelSizeZ/2.);
405 G4LogicalVolume* voxelLogical =
new G4LogicalVolume( zSlice, 0,
"LArVoxel" );
406 voxelLogical->SetVisAttributes(invisible);
407 new G4PVReplica(
"LArVoxel",
411 G4int( numberZvoxels ),
414 iVoxelVol = VoxelCache.emplace(VoxelSpecs,
415 VoxelVolumes_t(voxelBoxLogical, voxelLogical)
420 voxelLogical->SetSensitiveDetector(larVoxelReadout);
423 G4LogicalVolume* voxelBoxLogical = iVoxelVol->second.pBox;
433 G4double offsetInVoxelsX = voxelOffsetX /
voxelSizeX;
434 G4double offsetInVoxelsY = voxelOffsetY /
voxelSizeY;
435 G4double offsetInVoxelsZ = voxelOffsetZ /
voxelSizeZ;
436 G4double fractionOffsetX = offsetInVoxelsX - trunc(offsetInVoxelsX);
437 G4double fractionOffsetY = offsetInVoxelsY - trunc(offsetInVoxelsY);
438 G4double fractionOffsetZ = offsetInVoxelsZ - trunc(offsetInVoxelsZ);
439 G4double offsetX = fractionOffsetX *
voxelSizeX;
440 G4double offsetY = fractionOffsetY *
voxelSizeY;
441 G4double offsetZ = fractionOffsetZ *
voxelSizeZ;
446 transform = G4Translate3D( offsetX, offsetY, offsetZ ) * transform;
448 LOG_DEBUG(
"LArVoxelReadoutGeometry") <<
": offsetX=" << offsetX
449 <<
", offsetY=" << offsetY
450 <<
", offsetZ=" << offsetZ;
453 std::ostringstream nums;
454 nums <<
"_Cryostat" << c <<
"_TPC" << t;
459 "VoxelizationPhysicalVolume" + nums.str(),
465 { (
unsigned short int) c, (
unsigned short int) t }
472 LOG_DEBUG(
"LArVoxelReadoutGeometryDump") <<
"Dump of voxelized volume";
478 <<
"End of dump of voxelized volume";
double VoxelSizeX() const
Access to voxel dimensions and offsets.
int DumpPhysicalVolume(STREAM &out, const G4VPhysicalVolume &PV, std::string indentstr="")
larg4::LArVoxelReadout::Setup_t fReadoutSetupData
Data for LArVoxelReadout setup.
bool operator<(CryostatID const &a, CryostatID const &b)
Order cryostats with increasing ID.
static G4VPhysicalVolume * GetWorld()
art::ServiceHandle< geo::Geometry > fGeo
Handle to the geometry.
double VoxelSizeY() const
unsigned int Ncryostats() const
Returns the number of cryostats in the detector.
double VoxelSizeZ() const
std::unique_ptr< G4UserLimits > fStepLimit
constexpr bool DisableVoxelCaching
unsigned int NTPC() const
Number of TPCs in this cryostat.
CryostatGeo const & Cryostat(geo::CryostatID const &cryoid) const
Returns the specified cryostat.
G4PVPlacementWithID< TPCID_t > G4PVPlacementInTPC
A physical volume with a TPC ID.
double VoxelOffsetX() const
G4VPhysicalVolume * FindNestedVolume(G4VPhysicalVolume *mother, G4Transform3D &motherTransform, G4Transform3D &daughterTransform, std::string &daughterName, unsigned int expectedNum)
double VoxelOffsetZ() const
double VoxelOffsetY() const
cet::coded_exception< error, detail::translate > exception