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...
111 G4VPhysicalVolume* parallelPhysical = GetWorld();
119 G4Transform3D worldTransform;
122 std::string daughterName(
"volDetEnclosure");
123 G4Transform3D detEnclosureTransform;
126 detEnclosureTransform,
131 struct VoxelSpecs_t {
133 unsigned int nw, nh, nd;
136 bool operator<(
const VoxelSpecs_t& vs)
const 138 if (w < vs.w)
return true;
139 if (w > vs.w)
return false;
140 if (h < vs.h)
return true;
141 if (h > vs.h)
return false;
142 if (d < vs.d)
return true;
143 if (d > vs.d)
return false;
144 if (nw < vs.nw)
return true;
145 if (nw > vs.nw)
return false;
146 if (nh < vs.nh)
return true;
147 if (nh > vs.nh)
return false;
148 if (nd < vs.nd)
return true;
154 struct VoxelVolumes_t {
155 G4LogicalVolume* pBox;
156 G4LogicalVolume* pCell;
158 VoxelVolumes_t(G4LogicalVolume* box =
nullptr, G4LogicalVolume* cell =
nullptr)
159 : pBox(box), pCell(cell)
173 G4SDManager* sdManager = G4SDManager::GetSDMpointer();
177 using VoxelCache_t = std::map<VoxelSpecs_t, VoxelVolumes_t>;
178 VoxelCache_t VoxelCache;
183 daughterName =
"volCryostat";
184 G4Transform3D cryostatTransform;
186 detEnclosureVolume, detEnclosureTransform, cryostatTransform, daughterName, c);
191 daughterName =
"volTPC";
192 G4Transform3D tpcTransform;
193 G4VPhysicalVolume* tpcVolume =
194 FindNestedVolume(cryostatVolume, cryostatTransform, tpcTransform, daughterName, t);
196 daughterName =
"volTPCActive";
197 G4Transform3D transform;
198 G4VPhysicalVolume* larTPCPhysical =
202 G4LogicalVolume* larTPCLogical = larTPCPhysical->GetLogicalVolume();
203 larTPCLogical->SetUserLimits(
fStepLimit.get());
205 G4VSolid* larTPCShape = larTPCLogical->GetSolid();
217 G4double larTPCHalfXLength = 0;
218 G4double larTPCHalfYLength = 0;
219 G4double larTPCHalfZLength = 0;
220 G4Box* tpcBox =
dynamic_cast<G4Box*
>(larTPCShape);
222 larTPCHalfXLength = tpcBox->GetXHalfLength();
223 larTPCHalfYLength = tpcBox->GetYHalfLength();
224 larTPCHalfZLength = tpcBox->GetZHalfLength();
228 G4Tubs* tube =
dynamic_cast<G4Tubs*
>(larTPCShape);
230 larTPCHalfXLength = tube->GetOuterRadius();
231 larTPCHalfYLength = tube->GetOuterRadius();
232 larTPCHalfZLength = tube->GetZHalfLength();
236 <<
"Unknown shape in readout geometry" 237 <<
"The LAr TPC volume is not a box or a tube. " 238 <<
"This routine can't convert any other shapes.\n";
242 MF_LOG_DEBUG(
"LArVoxelReadoutGeometry") <<
": larTPCHalfXLength=" << larTPCHalfXLength
243 <<
": larTPCHalfYLength=" << larTPCHalfYLength
244 <<
": larTPCHalfZLength=" << larTPCHalfZLength;
252 G4double voxelOffsetX = lvc->
VoxelOffsetX() * CLHEP::cm;
253 G4double voxelOffsetY = lvc->
VoxelOffsetY() * CLHEP::cm;
254 G4double voxelOffsetZ = lvc->
VoxelOffsetZ() * CLHEP::cm;
257 <<
": voxelSizeX=" << voxelSizeX <<
", voxelSizeY=" << voxelSizeY
261 <<
": voxelOffsetX=" << voxelOffsetX <<
", voxelOffsetY=" << voxelOffsetY
262 <<
", voxelOffsetZ=" << voxelOffsetZ;
271 G4double numberXvoxels = 2. * larTPCHalfXLength /
voxelSizeX;
272 G4double numberYvoxels = 2. * larTPCHalfYLength /
voxelSizeY;
273 G4double numberZvoxels = 2. * larTPCHalfZLength /
voxelSizeZ;
274 numberXvoxels = trunc(numberXvoxels) + 1.;
275 numberYvoxels = trunc(numberYvoxels) + 1.;
276 numberZvoxels = trunc(numberZvoxels) + 1.;
279 <<
"Active volume of cryo #" << c <<
" TPC #" << t <<
" will be split in " 280 << numberXvoxels <<
" x " << numberYvoxels <<
" x " << numberZvoxels <<
" = " 281 << (numberXvoxels * numberYvoxels * numberZvoxels) <<
" voxels of size " << voxelSizeX
282 <<
" x " << voxelSizeY <<
" x " << voxelSizeZ <<
" cm";
284 VoxelSpecs_t VoxelSpecs{ 2. * larTPCHalfXLength,
285 2. * larTPCHalfYLength,
286 2. * larTPCHalfZLength,
287 (
unsigned int)numberXvoxels,
288 (
unsigned int)numberYvoxels,
289 (
unsigned int)numberZvoxels};
293 if (iVoxelVol == VoxelCache.end()) {
295 <<
"Creating a new voxel volume " << VoxelSpecs.w <<
" x " << VoxelSpecs.h <<
" x " 296 << VoxelSpecs.d <<
" cm, " << VoxelSpecs.nw <<
" x " << VoxelSpecs.nh <<
" x " 297 << VoxelSpecs.nd <<
" voxels";
299 G4double voxelBoxHalfX = numberXvoxels * voxelSizeX / 2.;
300 G4double voxelBoxHalfY = numberYvoxels * voxelSizeY / 2.;
301 G4double voxelBoxHalfZ = numberZvoxels * voxelSizeZ / 2.;
304 <<
": voxelBoxHalfX=" << voxelBoxHalfX <<
", voxelBoxHalfY=" << voxelBoxHalfY
305 <<
", voxelBoxHalfZ=" << voxelBoxHalfZ;
310 auto voxelBox =
new G4Box(
"VoxelBox", voxelBoxHalfX, voxelBoxHalfY, voxelBoxHalfZ);
311 auto voxelBoxLogical =
new G4LogicalVolume(voxelBox, 0,
"VoxelizationLogicalVolume");
315 auto invisible =
new G4VisAttributes();
316 invisible->SetVisibility(
false);
317 voxelBoxLogical->SetVisAttributes(invisible);
323 G4Box* xSlice =
new G4Box(
"xSlice", voxelSizeX / 2., voxelBoxHalfY, voxelBoxHalfZ);
324 G4LogicalVolume* xSliceLogical =
new G4LogicalVolume(xSlice, 0,
"xLArVoxelSlice");
325 xSliceLogical->SetVisAttributes(invisible);
328 new G4PVReplica(
"VoxelSlicesInX",
332 G4int(numberXvoxels),
336 auto ySlice =
new G4Box(
"ySlice", voxelSizeX / 2., voxelSizeY / 2., voxelBoxHalfZ);
337 auto ySliceLogical =
new G4LogicalVolume(ySlice, 0,
"yLArVoxelSlice");
338 ySliceLogical->SetVisAttributes(invisible);
339 new G4PVReplica(
"VoxelSlicesInY",
343 G4int(numberYvoxels),
348 auto zSlice =
new G4Box(
"zSlice", voxelSizeX / 2., voxelSizeY / 2., voxelSizeZ / 2.);
349 auto voxelLogical =
new G4LogicalVolume(zSlice, 0,
"LArVoxel");
350 voxelLogical->SetVisAttributes(invisible);
352 "LArVoxel", voxelLogical, ySliceLogical, kZAxis, G4int(numberZvoxels), voxelSizeZ);
354 iVoxelVol = VoxelCache.emplace(VoxelSpecs, VoxelVolumes_t(voxelBoxLogical, voxelLogical))
362 G4LogicalVolume* voxelBoxLogical = iVoxelVol->second.pBox;
372 G4double offsetInVoxelsX = voxelOffsetX /
voxelSizeX;
373 G4double offsetInVoxelsY = voxelOffsetY /
voxelSizeY;
374 G4double offsetInVoxelsZ = voxelOffsetZ /
voxelSizeZ;
375 G4double fractionOffsetX = offsetInVoxelsX - trunc(offsetInVoxelsX);
376 G4double fractionOffsetY = offsetInVoxelsY - trunc(offsetInVoxelsY);
377 G4double fractionOffsetZ = offsetInVoxelsZ - trunc(offsetInVoxelsZ);
378 G4double offsetX = fractionOffsetX *
voxelSizeX;
379 G4double offsetY = fractionOffsetY *
voxelSizeY;
380 G4double offsetZ = fractionOffsetZ *
voxelSizeZ;
385 transform = G4Translate3D(offsetX, offsetY, offsetZ) * transform;
388 <<
": offsetX=" << offsetX <<
", offsetY=" << offsetY <<
", offsetZ=" << offsetZ;
391 std::ostringstream nums;
392 nums <<
"_Cryostat" << c <<
"_TPC" << t;
397 "VoxelizationPhysicalVolume" + nums.str(),
403 {(
unsigned short int)c, (
unsigned short int)t}
410 MF_LOG_DEBUG(
"LArVoxelReadoutGeometryDump") <<
"Dump of voxelized volume";
413 DumpPhysicalVolume(log, *parallelPhysical);
415 MF_LOG_DEBUG(
"LArVoxelReadoutGeometryDump") <<
"End of dump of voxelized volume";
double VoxelSizeX() const
Access to voxel dimensions and offsets.
larg4::LArVoxelReadout::Setup_t fReadoutSetupData
G4VPhysicalVolume * FindNestedVolume(G4VPhysicalVolume *mother, G4Transform3D &motherTransform, G4Transform3D &daughterTransform, std::string const &daughterName, unsigned int expectedNum)
constexpr bool operator<(CryostatID const &a, CryostatID const &b)
Order cryostats with increasing ID.
static G4VPhysicalVolume * GetWorld()
double VoxelSizeY() const
void Setup(Setup_t const &setupData)
Reads all the configuration elements from setupData
larg4::LArVoxelReadout * flarVoxelReadout
Data for LArVoxelReadout setup.
unsigned int Ncryostats() const
Returns the number of cryostats in the detector.
CryostatGeo const & Cryostat(CryostatID const &cryoid=cryostat_zero) const
Returns the specified cryostat.
double VoxelSizeZ() const
void SetSingleTPC(unsigned int cryostat, unsigned int tpc)
Associates this readout to one specific TPC.
std::unique_ptr< G4UserLimits > fStepLimit
constexpr bool DisableVoxelCaching
unsigned int NTPC() const
Number of TPCs in this cryostat.
G4PVPlacementWithID< TPCID_t > G4PVPlacementInTPC
A physical volume with a TPC ID.
double VoxelOffsetX() const
art::ServiceHandle< geo::Geometry const > fGeo
Handle to the geometry.
double VoxelOffsetZ() const
double VoxelOffsetY() const
cet::coded_exception< error, detail::translate > exception
The data type to uniquely identify a cryostat.